H5 SDK reference
soduwork-app.js (version 1.6) connects an app page to SoduWork. Copy it from client/sdk/soduwork-app.js into your app and load it before your own script. It works in native app pages and in iframes the app explicitly authorizes.
<script src="soduwork-app.js"></script>
Every method returns a promise of a receipt. Check ok and show reason when it is false.
Capabilities
Declare each capability your page uses in source.bridge.capabilities. Calls without the matching capability are refused.
| Capability | Methods |
|---|---|
context.read | context.get(), user.getCurrent() |
conversation.send | chat.send() |
composer.control | chat.insertText(), chat.expand(), chat.collapse(), attachments.* |
settings.read / settings.write | settings.get() / settings.update() |
automation.create | automation.create() |
data.read / data.write | data.apps(), data.get(), data.list(), data.assetGet() / data.batch(), data.assetPut() |
messages.read | conversations.list(), conversations.messages(), notifications.list() |
library.read | library.list(), library.read() |
directory.read | directory.list() |
notifications.send | chat.mention() |
mcp.connect | mcp.connect() |
ai.generate | ai.generate() |
Context
context.get() returns an app and tab context, the current conversation ID when there is one, and locale (for example en-US), which is the main window's language. Use it to choose your page's language; fall back to English if it's missing. It doesn't translate your data or override a language the user picked on your page.
Send to the side panel
const receipt = await soduWorkApp.chat.send({
text: 'Summarize the selected record',
requestId: soduWorkApp.createRequestId(),
attachmentIds: [] // optional
});
okmeans the conversation accepted the message. It doesn't mean the model has finished.- Text is limited to 8,000 characters.
- Reuse the same
requestIdwhen retrying the same action; a message that was sent isn't run twice. Use a new one for a new action. - If a call times out, check the side panel before sending again.
events.onRefresh(callback) runs when a turn in the side panel settles. Reload your data there. A turn can also settle after a failure or cancel, so a refresh doesn't mean the work succeeded.
Attachments
attachments.pick() opens the system file picker and returns references (ID, name, MIME type and size), never file bytes or paths. attachments.importFile(file) stages a pasted or dropped file. Pass the IDs to chat.send, and call attachments.release(ids) when you no longer need them.
- Up to 20 attachments and 256 MiB per page.
- A changed or deleted source file, an unfinished upload or an unknown ID blocks the send.
- Attachment IDs are temporary. To keep a file in your app, read its bytes and use
data.assetPut.
Settings
const state = await soduWorkApp.settings.get();
const saved = await soduWorkApp.settings.update({
values: { theme: 'dark', pageSize: 20 },
expectedRevision: state.revision
});
Settings are separated by SoduWork account, app and page origin, and encrypted with the system's secure storage. Values can be any JSON, up to 100 keys, 64 KiB and 8 levels deep. update merges top-level keys; use remove: ['key'] to delete one. List sensitive keys in secretKeys so normal reads hide them.
Settings are not single sign-on, and they don't create a settings form for you.
Schedules
await soduWorkApp.automation.create({
text: 'Every weekday at 9:00, collect yesterday\'s orders and summarize them',
requestId: soduWorkApp.createRequestId()
});
- Supported timing: daily, weekly on a given day, hourly, or once on a date. Without a time, the default is 18:00 Beijing time; tell the user that.
- Text is limited to 8,000 characters.
- A successful receipt means the schedule was saved, not that it ran.
- The SDK can't list, pause or delete schedules.
- Show business words in your UI ("Daily summary", "Subscribe"), not "automation".
App data
data.get, data.list and data.batch read and write records in your app's collections. data.assetPut and data.assetGet store files. Writes check expectedRevision; on a conflict, read again and merge. data.apps() lists apps on the same account that you can read. Pages and the app's Skills share the same data.
Colleagues and mentions
directory.list() returns colleagues you can see, with their organization units, up to 500 per call. It never includes your own account, credentials, phone numbers or emails. chat.mention({ recipientUserId, text }) opens a card in the side panel; the user checks it and sends the notification. Text is limited to 500 characters.
Quick AI
ai.generate({ input, instructions }) returns { ok, text, model, usage, finishReason } directly to the page, without a conversation, tools or history. Use it for small tasks like a title or a tag. Model authorization, quota and usage tracking still apply. Don't retry automatically when the result is uncertain.
Iframes
To let an iframe on another origin use the SDK, authorize its exact origin in the app's top page, and set the parent's origin in the iframe:
// app top page
soduWorkApp.configure({ allowedFrameOrigins: ['https://business.example'] });
// inside the iframe
soduWorkApp.configure({ parentOrigin: 'https://shell.example' });
Wildcards and opaque origins are not accepted. Iframes can't forward mcp.connect, local paths or IPC.
Outside SoduWork
In a normal browser without the SoduWork app window, calls fail with "not connected". The SDK doesn't register a custom URL protocol.