@doist/automations-cli 1.22.2 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
collectSkillStatus,
|
|
8
8
|
getInstaller,
|
|
9
9
|
updateAllInstalledSkills
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-DECO7WSK.js";
|
|
11
11
|
|
|
12
12
|
// ../../node_modules/ajv/dist/compile/codegen/code.js
|
|
13
13
|
var require_code = __commonJS({
|
|
@@ -6899,7 +6899,7 @@ import { fileURLToPath } from "node:url";
|
|
|
6899
6899
|
// package.json
|
|
6900
6900
|
var package_default = {
|
|
6901
6901
|
name: "@doist/automations-cli",
|
|
6902
|
-
version: "1.
|
|
6902
|
+
version: "1.23.0",
|
|
6903
6903
|
description: "Command-line client for Todoist Automations",
|
|
6904
6904
|
type: "module",
|
|
6905
6905
|
bin: {
|
|
@@ -6933,7 +6933,7 @@ var package_default = {
|
|
|
6933
6933
|
build: "node scripts/build.mjs && node scripts/refresh-skills.mjs",
|
|
6934
6934
|
dev: "node scripts/build.mjs --watch",
|
|
6935
6935
|
"type-check": "tsc -p tsconfig.test.json --noEmit",
|
|
6936
|
-
test: "vitest run",
|
|
6936
|
+
test: "vitest run && node --test '../../release/*.test.mjs'",
|
|
6937
6937
|
check: "oxfmt src scripts --check && oxlint src scripts && npm run check:skill-sync",
|
|
6938
6938
|
"check:fix": "oxfmt src scripts && oxlint src scripts --fix",
|
|
6939
6939
|
"sync:skill": "node scripts/sync-skill.mjs",
|
|
@@ -6957,7 +6957,6 @@ var package_default = {
|
|
|
6957
6957
|
"conventional-changelog-conventionalcommits": "9.3.1",
|
|
6958
6958
|
esbuild: "0.28.2",
|
|
6959
6959
|
"semantic-release": "25.0.9",
|
|
6960
|
-
"semantic-release-monorepo": "8.0.2",
|
|
6961
6960
|
typescript: "6.0.3",
|
|
6962
6961
|
vitest: "5.0.5"
|
|
6963
6962
|
},
|
|
@@ -27230,7 +27229,7 @@ var AutomationRunDtoSchema = external_exports.discriminatedUnion("status", [
|
|
|
27230
27229
|
...automationRunDtoBaseShape,
|
|
27231
27230
|
status: external_exports.literal("skipped"),
|
|
27232
27231
|
skipReason: external_exports.string().nullish(),
|
|
27233
|
-
skipCategory: external_exports.enum(SKIP_CATEGORIES).nullish()
|
|
27232
|
+
skipCategory: external_exports.enum(SKIP_CATEGORIES).nullish().catch(null)
|
|
27234
27233
|
})
|
|
27235
27234
|
]);
|
|
27236
27235
|
var automationRunListResponseSchema = external_exports.object({
|
|
@@ -27332,7 +27331,7 @@ var AutomationRunDetailDtoSchema = external_exports.discriminatedUnion("status",
|
|
|
27332
27331
|
...automationRunDetailDtoBaseShape,
|
|
27333
27332
|
status: external_exports.literal("skipped"),
|
|
27334
27333
|
skipReason: external_exports.string().nullish(),
|
|
27335
|
-
skipCategory: external_exports.enum(SKIP_CATEGORIES).nullish()
|
|
27334
|
+
skipCategory: external_exports.enum(SKIP_CATEGORIES).nullish().catch(null)
|
|
27336
27335
|
})
|
|
27337
27336
|
]);
|
|
27338
27337
|
function summarizeToolCallArgumentKeys(args) {
|
|
@@ -29157,7 +29156,7 @@ var runStatusSchema = external_exports.discriminatedUnion("status", [
|
|
|
29157
29156
|
status: external_exports.literal("skipped"),
|
|
29158
29157
|
lastRun: external_exports.iso.datetime(),
|
|
29159
29158
|
skipReason: external_exports.string().optional(),
|
|
29160
|
-
skipCategory: external_exports.enum(SKIP_CATEGORIES).optional()
|
|
29159
|
+
skipCategory: external_exports.enum(SKIP_CATEGORIES).optional().catch(void 0)
|
|
29161
29160
|
})
|
|
29162
29161
|
]);
|
|
29163
29162
|
var automationSchema = external_exports.object({
|
|
@@ -30080,7 +30079,7 @@ var DraftTestRunDetailDtoSchema = external_exports.discriminatedUnion("status",
|
|
|
30080
30079
|
...draftTestRunDetailDtoBaseShape,
|
|
30081
30080
|
status: external_exports.literal("skipped"),
|
|
30082
30081
|
skipReason: external_exports.string().nullish(),
|
|
30083
|
-
skipCategory: external_exports.enum(SKIP_CATEGORIES).nullish()
|
|
30082
|
+
skipCategory: external_exports.enum(SKIP_CATEGORIES).nullish().catch(null)
|
|
30084
30083
|
})
|
|
30085
30084
|
]);
|
|
30086
30085
|
|
|
@@ -31771,7 +31770,8 @@ var workspaceAutomationsEndpoints = {
|
|
|
31771
31770
|
visibility: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/visibility`,
|
|
31772
31771
|
move: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/move`,
|
|
31773
31772
|
trigger: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/trigger`,
|
|
31774
|
-
draft: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/draft
|
|
31773
|
+
draft: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/draft`,
|
|
31774
|
+
duplicate: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/duplicate`
|
|
31775
31775
|
};
|
|
31776
31776
|
function root8(workspaceId) {
|
|
31777
31777
|
return `/workspaces/${encodeURIComponent(workspaceId)}/automations`;
|
|
@@ -31884,6 +31884,15 @@ var WorkspaceAutomationsClient = class extends BaseClient {
|
|
|
31884
31884
|
* Opens an edit draft seeded from the published manifest. Answers 409 when
|
|
31885
31885
|
* one is already open; see `getOpenDraftConflictError`.
|
|
31886
31886
|
*/
|
|
31887
|
+
/** A draft copy of the automation, in the same workspace, for the caller to edit. */
|
|
31888
|
+
async duplicate(workspaceId, id, options) {
|
|
31889
|
+
const data = await this.request({
|
|
31890
|
+
method: "POST",
|
|
31891
|
+
path: workspaceAutomationsEndpoints.duplicate(IdSchema.parse(workspaceId), IdSchema.parse(id)),
|
|
31892
|
+
options
|
|
31893
|
+
});
|
|
31894
|
+
return automationDraftWithValidationSchema.parse(data);
|
|
31895
|
+
}
|
|
31887
31896
|
async createDraft(workspaceId, id, options) {
|
|
31888
31897
|
const data = await this.request({
|
|
31889
31898
|
method: "POST",
|
|
@@ -34696,6 +34705,491 @@ function addWorkspaceScopeOptions(command) {
|
|
|
34696
34705
|
).option("--personal", "Act on your personal space, ignoring any pinned workspace");
|
|
34697
34706
|
}
|
|
34698
34707
|
|
|
34708
|
+
// ../../packages/sdk/dist/esm/chat-turn/connection-requirements.js
|
|
34709
|
+
var CONNECTION_LOOKUP_CONCURRENCY = 4;
|
|
34710
|
+
function deduplicateConnectionRequirements(requirements) {
|
|
34711
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34712
|
+
return requirements.filter((requirement) => {
|
|
34713
|
+
const key = JSON.stringify([requirement.connectorId, requirement.connectionType]);
|
|
34714
|
+
if (seen.has(key))
|
|
34715
|
+
return false;
|
|
34716
|
+
seen.add(key);
|
|
34717
|
+
return true;
|
|
34718
|
+
});
|
|
34719
|
+
}
|
|
34720
|
+
async function loadConnectionRequirements(connections, requirements, options) {
|
|
34721
|
+
return mapWithConcurrency(deduplicateConnectionRequirements(requirements), CONNECTION_LOOKUP_CONCURRENCY, async (requirement) => {
|
|
34722
|
+
const response = await connections.list({
|
|
34723
|
+
connectorId: requirement.connectorId,
|
|
34724
|
+
capability: requirement.connectionType,
|
|
34725
|
+
status: "authorized"
|
|
34726
|
+
}, options);
|
|
34727
|
+
return {
|
|
34728
|
+
...requirement,
|
|
34729
|
+
availableConnections: response.connections.map((connection) => ({
|
|
34730
|
+
id: connection.id,
|
|
34731
|
+
label: connection.accountDisplayLabel ?? connection.name ?? connection.id
|
|
34732
|
+
}))
|
|
34733
|
+
};
|
|
34734
|
+
});
|
|
34735
|
+
}
|
|
34736
|
+
async function mapWithConcurrency(items, concurrency, map2) {
|
|
34737
|
+
const results = new Array(items.length);
|
|
34738
|
+
let next = 0;
|
|
34739
|
+
const workers = Array.from({ length: Math.min(concurrency, items.length) }, async () => {
|
|
34740
|
+
while (next < items.length) {
|
|
34741
|
+
const index = next;
|
|
34742
|
+
next += 1;
|
|
34743
|
+
results[index] = await map2(items[index]);
|
|
34744
|
+
}
|
|
34745
|
+
});
|
|
34746
|
+
await Promise.all(workers);
|
|
34747
|
+
return results;
|
|
34748
|
+
}
|
|
34749
|
+
|
|
34750
|
+
// ../../packages/sdk/dist/esm/chat-turn/connection-setup.js
|
|
34751
|
+
async function startConnectionSetup(connections, request2, options) {
|
|
34752
|
+
const created = await connections.create({
|
|
34753
|
+
connectorId: request2.connectorId,
|
|
34754
|
+
capability: request2.capability,
|
|
34755
|
+
...request2.automationIds?.length ? { body: { automationIds: [...request2.automationIds] } } : {}
|
|
34756
|
+
}, options);
|
|
34757
|
+
return { connectionId: created.connectionId, setup: created.setup, resumed: false };
|
|
34758
|
+
}
|
|
34759
|
+
function summarizeConnectionSetup(setup) {
|
|
34760
|
+
if (setup?.kind === "oauth") {
|
|
34761
|
+
return { setupKind: "oauth", authorizationUrl: setup.authorizationUrl };
|
|
34762
|
+
}
|
|
34763
|
+
if (setup?.kind === "managed") {
|
|
34764
|
+
return {
|
|
34765
|
+
setupKind: "managed",
|
|
34766
|
+
instructions: setup.instructions,
|
|
34767
|
+
code: setup.code,
|
|
34768
|
+
deepLinkUrl: setup.deepLinkUrl,
|
|
34769
|
+
expiresAt: setup.expiresAt
|
|
34770
|
+
};
|
|
34771
|
+
}
|
|
34772
|
+
return { setupKind: "none" };
|
|
34773
|
+
}
|
|
34774
|
+
function getConnectionSetupUrl(setup) {
|
|
34775
|
+
if (setup?.kind === "oauth")
|
|
34776
|
+
return setup.authorizationUrl;
|
|
34777
|
+
if (setup?.kind === "managed")
|
|
34778
|
+
return setup.deepLinkUrl;
|
|
34779
|
+
return null;
|
|
34780
|
+
}
|
|
34781
|
+
|
|
34782
|
+
// ../../packages/core/dist/esm/chat-tools/client-tool-result.js
|
|
34783
|
+
var clientToolContinuationPartSchema = external_exports.discriminatedUnion("type", [
|
|
34784
|
+
toolPromptEnablePushResultSchema.omit({ input: true }).strict(),
|
|
34785
|
+
toolSelectConnectionsResultSchema.omit({ input: true }).strict()
|
|
34786
|
+
]);
|
|
34787
|
+
|
|
34788
|
+
// ../../packages/core/dist/esm/chat-tools/update-memory.js
|
|
34789
|
+
var UpdateMemoryInputSchema = external_exports.object({
|
|
34790
|
+
append: external_exports.string().min(1).optional(),
|
|
34791
|
+
replace: external_exports.object({
|
|
34792
|
+
old: external_exports.string().min(1),
|
|
34793
|
+
new: external_exports.string()
|
|
34794
|
+
}).optional()
|
|
34795
|
+
});
|
|
34796
|
+
var UpdateMemoryOutputSchema = external_exports.object({
|
|
34797
|
+
memory: external_exports.string().nullable(),
|
|
34798
|
+
// What the memory held before this write — the chat UI's Undo restores it.
|
|
34799
|
+
previousMemory: external_exports.string().nullable()
|
|
34800
|
+
});
|
|
34801
|
+
var toolUpdateMemorySchema = external_exports.object({
|
|
34802
|
+
type: external_exports.literal("tool-update-memory"),
|
|
34803
|
+
toolCallId: external_exports.string().min(1),
|
|
34804
|
+
state: external_exports.literal("input-available"),
|
|
34805
|
+
input: UpdateMemoryInputSchema
|
|
34806
|
+
});
|
|
34807
|
+
var toolUpdateMemoryResultSchema = external_exports.object({
|
|
34808
|
+
type: external_exports.literal("tool-update-memory"),
|
|
34809
|
+
toolCallId: external_exports.string().min(1),
|
|
34810
|
+
state: external_exports.literal("output-available"),
|
|
34811
|
+
input: UpdateMemoryInputSchema,
|
|
34812
|
+
output: UpdateMemoryOutputSchema
|
|
34813
|
+
});
|
|
34814
|
+
|
|
34815
|
+
// ../../packages/sdk/dist/esm/chat-turn/messages.js
|
|
34816
|
+
var persistedToolPartSchema = external_exports.object({
|
|
34817
|
+
type: external_exports.string().trim().min(6).refine((type) => type.startsWith("tool-")),
|
|
34818
|
+
toolCallId: external_exports.string().trim().min(1),
|
|
34819
|
+
state: external_exports.enum(["input-streaming", "input-available", "output-available", "output-error"])
|
|
34820
|
+
}).passthrough();
|
|
34821
|
+
function createUserMessage(text2) {
|
|
34822
|
+
return {
|
|
34823
|
+
id: globalThis.crypto.randomUUID(),
|
|
34824
|
+
role: "user",
|
|
34825
|
+
parts: [{ type: "text", text: text2 }]
|
|
34826
|
+
};
|
|
34827
|
+
}
|
|
34828
|
+
function toUiMessage(message) {
|
|
34829
|
+
if (message.role !== "user" && message.role !== "assistant" && message.role !== "system") {
|
|
34830
|
+
throw new Error(`Unsupported persisted chat role: ${message.role}`);
|
|
34831
|
+
}
|
|
34832
|
+
if (!Array.isArray(message.parts)) {
|
|
34833
|
+
throw new Error(`Persisted chat message ${message.messageId} has invalid parts.`);
|
|
34834
|
+
}
|
|
34835
|
+
return {
|
|
34836
|
+
id: message.messageId,
|
|
34837
|
+
role: message.role,
|
|
34838
|
+
parts: normalizePersistedMessageParts(message.parts)
|
|
34839
|
+
};
|
|
34840
|
+
}
|
|
34841
|
+
function normalizePersistedMessageParts(parts) {
|
|
34842
|
+
return parts.filter((part) => isTextPart(part) || isStepStartPart(part) || isReasoningPart(part) || persistedToolPartSchema.safeParse(part).success);
|
|
34843
|
+
}
|
|
34844
|
+
function isTextPart(part) {
|
|
34845
|
+
if (typeof part !== "object" || part === null) {
|
|
34846
|
+
return false;
|
|
34847
|
+
}
|
|
34848
|
+
const candidate = part;
|
|
34849
|
+
return candidate.type === "text" && typeof candidate.text === "string";
|
|
34850
|
+
}
|
|
34851
|
+
function isStepStartPart(part) {
|
|
34852
|
+
if (typeof part !== "object" || part === null) {
|
|
34853
|
+
return false;
|
|
34854
|
+
}
|
|
34855
|
+
return part.type === "step-start";
|
|
34856
|
+
}
|
|
34857
|
+
function isReasoningPart(part) {
|
|
34858
|
+
if (typeof part !== "object" || part === null) {
|
|
34859
|
+
return false;
|
|
34860
|
+
}
|
|
34861
|
+
const candidate = part;
|
|
34862
|
+
return candidate.type === "reasoning" && typeof candidate.text === "string" && (candidate.state === void 0 || candidate.state === "streaming" || candidate.state === "done");
|
|
34863
|
+
}
|
|
34864
|
+
function getVisibleText(message) {
|
|
34865
|
+
return message.parts.filter((part) => part.type === "text").map((part) => part.text).join("");
|
|
34866
|
+
}
|
|
34867
|
+
function getPendingClientAction(message) {
|
|
34868
|
+
for (let index = message.parts.length - 1; index >= 0; index -= 1) {
|
|
34869
|
+
const part = message.parts[index];
|
|
34870
|
+
if (isSelectConnections(part)) {
|
|
34871
|
+
return {
|
|
34872
|
+
kind: "select_connections",
|
|
34873
|
+
message,
|
|
34874
|
+
toolCallId: part.toolCallId,
|
|
34875
|
+
draftId: part.input.draftId,
|
|
34876
|
+
connections: part.input.connections
|
|
34877
|
+
};
|
|
34878
|
+
}
|
|
34879
|
+
if (isPromptEnablePush(part)) {
|
|
34880
|
+
return {
|
|
34881
|
+
kind: "enable_push",
|
|
34882
|
+
message,
|
|
34883
|
+
toolCallId: part.toolCallId,
|
|
34884
|
+
draftId: part.input.draftId
|
|
34885
|
+
};
|
|
34886
|
+
}
|
|
34887
|
+
}
|
|
34888
|
+
return null;
|
|
34889
|
+
}
|
|
34890
|
+
function getPendingActionFromMessages(messages) {
|
|
34891
|
+
const latestMessage = messages.at(-1);
|
|
34892
|
+
if (!latestMessage || latestMessage.role !== "assistant")
|
|
34893
|
+
return null;
|
|
34894
|
+
return getPendingClientAction(toUiMessage(latestMessage));
|
|
34895
|
+
}
|
|
34896
|
+
function getPublishedAutomationId(message) {
|
|
34897
|
+
for (let index = message.parts.length - 1; index >= 0; index -= 1) {
|
|
34898
|
+
const part = message.parts[index];
|
|
34899
|
+
if (isPublishDraftResult(part) && part.output.success) {
|
|
34900
|
+
return part.output.automationId;
|
|
34901
|
+
}
|
|
34902
|
+
}
|
|
34903
|
+
return void 0;
|
|
34904
|
+
}
|
|
34905
|
+
function createEnablePushContinuation(action, output2) {
|
|
34906
|
+
return {
|
|
34907
|
+
id: action.message.id,
|
|
34908
|
+
role: "assistant",
|
|
34909
|
+
parts: [
|
|
34910
|
+
{
|
|
34911
|
+
type: "tool-prompt-enable-push-notifications",
|
|
34912
|
+
toolCallId: action.toolCallId,
|
|
34913
|
+
state: "output-available",
|
|
34914
|
+
output: output2
|
|
34915
|
+
}
|
|
34916
|
+
]
|
|
34917
|
+
};
|
|
34918
|
+
}
|
|
34919
|
+
function createSelectConnectionsContinuation(action, output2) {
|
|
34920
|
+
return {
|
|
34921
|
+
id: action.message.id,
|
|
34922
|
+
role: "assistant",
|
|
34923
|
+
parts: [
|
|
34924
|
+
{
|
|
34925
|
+
type: "tool-select-connections",
|
|
34926
|
+
toolCallId: action.toolCallId,
|
|
34927
|
+
state: "output-available",
|
|
34928
|
+
output: output2
|
|
34929
|
+
}
|
|
34930
|
+
]
|
|
34931
|
+
};
|
|
34932
|
+
}
|
|
34933
|
+
|
|
34934
|
+
// ../../packages/sdk/dist/esm/chat-turn/types.js
|
|
34935
|
+
var ChatTurnInputError = class extends Error {
|
|
34936
|
+
code;
|
|
34937
|
+
constructor(code, message) {
|
|
34938
|
+
super(message);
|
|
34939
|
+
this.name = "ChatTurnInputError";
|
|
34940
|
+
this.code = code;
|
|
34941
|
+
}
|
|
34942
|
+
};
|
|
34943
|
+
|
|
34944
|
+
// ../../packages/sdk/dist/esm/chat-turn/run-conversation-turn.js
|
|
34945
|
+
async function runConversationTurn(options) {
|
|
34946
|
+
const { api, transport, conversationId, signal } = options;
|
|
34947
|
+
const workspaceId = options.workspaceId ?? null;
|
|
34948
|
+
const requestOptions = { signal };
|
|
34949
|
+
const pending = await readPendingAction(options);
|
|
34950
|
+
let nextMessage;
|
|
34951
|
+
if (pending?.kind === "enable_push") {
|
|
34952
|
+
if ("message" in options.input || options.input.selections.length > 0) {
|
|
34953
|
+
throw new ChatTurnInputError("awaiting_push", "The conversation is waiting for the push notification prompt to be answered.");
|
|
34954
|
+
}
|
|
34955
|
+
nextMessage = await answerEnablePush(options, pending);
|
|
34956
|
+
} else if ("message" in options.input) {
|
|
34957
|
+
if (pending?.kind === "select_connections") {
|
|
34958
|
+
throw new ChatTurnInputError("awaiting_selection", "The conversation is waiting for connection selection.");
|
|
34959
|
+
}
|
|
34960
|
+
nextMessage = createUserMessage(options.input.message);
|
|
34961
|
+
} else {
|
|
34962
|
+
const selections = options.input.selections;
|
|
34963
|
+
if (pending?.kind !== "select_connections") {
|
|
34964
|
+
throw new ChatTurnInputError(selections.length > 0 ? "not_awaiting_selection" : "input_required", selections.length > 0 ? "The conversation is not waiting for connection selection." : "A message is required to continue.");
|
|
34965
|
+
}
|
|
34966
|
+
const resolution = await resolveSelectConnections(options, pending, selections);
|
|
34967
|
+
if (resolution.kind === "required") {
|
|
34968
|
+
return actionRequired(conversationId, getVisibleText(pending.message), resolution.pendingAction);
|
|
34969
|
+
}
|
|
34970
|
+
nextMessage = resolution.continuation;
|
|
34971
|
+
}
|
|
34972
|
+
while (true) {
|
|
34973
|
+
const response = await transport.streamTurn({
|
|
34974
|
+
conversationId,
|
|
34975
|
+
workspaceId,
|
|
34976
|
+
message: nextMessage,
|
|
34977
|
+
signal,
|
|
34978
|
+
onText: options.onText,
|
|
34979
|
+
onToolActivity: options.onToolActivity
|
|
34980
|
+
});
|
|
34981
|
+
const assistantText = getVisibleText(response);
|
|
34982
|
+
const automationId = getPublishedAutomationId(response);
|
|
34983
|
+
if (automationId) {
|
|
34984
|
+
options.onPublished?.(automationId);
|
|
34985
|
+
const archive = await archiveConversation(api, conversationId, requestOptions);
|
|
34986
|
+
return {
|
|
34987
|
+
conversationId,
|
|
34988
|
+
outcome: "published",
|
|
34989
|
+
assistantText,
|
|
34990
|
+
automationId,
|
|
34991
|
+
...archive
|
|
34992
|
+
};
|
|
34993
|
+
}
|
|
34994
|
+
const responseAction = getPendingClientAction(response);
|
|
34995
|
+
if (responseAction?.kind === "select_connections") {
|
|
34996
|
+
const resolution = await resolveSelectConnections(options, responseAction, []);
|
|
34997
|
+
if (resolution.kind === "resolved") {
|
|
34998
|
+
nextMessage = resolution.continuation;
|
|
34999
|
+
continue;
|
|
35000
|
+
}
|
|
35001
|
+
return actionRequired(conversationId, assistantText, resolution.pendingAction);
|
|
35002
|
+
}
|
|
35003
|
+
if (responseAction?.kind === "enable_push") {
|
|
35004
|
+
return actionRequired(conversationId, assistantText, {
|
|
35005
|
+
kind: "enable_push",
|
|
35006
|
+
toolCallId: responseAction.toolCallId,
|
|
35007
|
+
draftId: responseAction.draftId
|
|
35008
|
+
});
|
|
35009
|
+
}
|
|
35010
|
+
return { conversationId, outcome: "awaiting_input", assistantText };
|
|
35011
|
+
}
|
|
35012
|
+
}
|
|
35013
|
+
async function answerEnablePush(options, action) {
|
|
35014
|
+
const { subscriptions } = await options.api.notifications.push.list({
|
|
35015
|
+
signal: options.signal
|
|
35016
|
+
});
|
|
35017
|
+
const deviceCount = subscriptions.length;
|
|
35018
|
+
return createEnablePushContinuation(action, {
|
|
35019
|
+
enabled: deviceCount > 0,
|
|
35020
|
+
deviceCount,
|
|
35021
|
+
message: deviceCount > 0 ? `Push notifications are enabled on ${deviceCount} device${deviceCount === 1 ? "" : "s"}.` : "The user has not enabled push notifications."
|
|
35022
|
+
});
|
|
35023
|
+
}
|
|
35024
|
+
async function readPendingAction(options) {
|
|
35025
|
+
if (options.pendingAction !== void 0)
|
|
35026
|
+
return options.pendingAction;
|
|
35027
|
+
const messages = await options.api.chat.getMessages(options.conversationId, {
|
|
35028
|
+
signal: options.signal
|
|
35029
|
+
});
|
|
35030
|
+
return getPendingActionFromMessages(messages);
|
|
35031
|
+
}
|
|
35032
|
+
function actionRequired(conversationId, assistantText, pendingAction) {
|
|
35033
|
+
return { conversationId, outcome: "action_required", assistantText, pendingAction };
|
|
35034
|
+
}
|
|
35035
|
+
async function archiveConversation(api, conversationId, requestOptions) {
|
|
35036
|
+
try {
|
|
35037
|
+
const conversation = await api.chat.updateConversation(conversationId, { isArchived: true }, requestOptions);
|
|
35038
|
+
if (!conversation.isArchived) {
|
|
35039
|
+
throw new Error("The Automations API returned an active conversation.");
|
|
35040
|
+
}
|
|
35041
|
+
return { conversationArchived: true };
|
|
35042
|
+
} catch (error62) {
|
|
35043
|
+
return {
|
|
35044
|
+
conversationArchived: false,
|
|
35045
|
+
conversationArchiveError: error62 instanceof Error ? error62.message : String(error62)
|
|
35046
|
+
};
|
|
35047
|
+
}
|
|
35048
|
+
}
|
|
35049
|
+
async function resolveSelectConnections(options, action, selections) {
|
|
35050
|
+
const { api, signal } = options;
|
|
35051
|
+
const requestOptions = { signal };
|
|
35052
|
+
const requirements = await loadConnectionRequirements(api.connections, action.connections, requestOptions);
|
|
35053
|
+
assertSelectionsUnambiguous(requirements, selections);
|
|
35054
|
+
const resolved = [];
|
|
35055
|
+
for (const requirement of requirements) {
|
|
35056
|
+
const explicit = selections.find((selection) => selection.connectorId === requirement.connectorId && (!selection.connectionType || selection.connectionType === requirement.connectionType));
|
|
35057
|
+
let connectionId = explicit?.connectionId;
|
|
35058
|
+
let setup;
|
|
35059
|
+
if (connectionId) {
|
|
35060
|
+
const exists = requirement.availableConnections.some((connection) => connection.id === connectionId);
|
|
35061
|
+
if (!exists) {
|
|
35062
|
+
throw new ChatTurnInputError("unknown_connection", `Connection ${connectionId} is not an authorized ${requirement.serviceName} connection.`);
|
|
35063
|
+
}
|
|
35064
|
+
} else if (requirement.availableConnections.length === 1) {
|
|
35065
|
+
connectionId = requirement.availableConnections[0]?.id;
|
|
35066
|
+
} else if (requirement.availableConnections.length > 1) {
|
|
35067
|
+
connectionId = await options.chooseConnection?.(requirement);
|
|
35068
|
+
} else if (options.authorizeConnection) {
|
|
35069
|
+
connectionId = await options.authorizeConnection(requirement);
|
|
35070
|
+
} else {
|
|
35071
|
+
setup = await startConnectionSetup(api.connections, { connectorId: requirement.connectorId, capability: requirement.connectionType }, requestOptions);
|
|
35072
|
+
}
|
|
35073
|
+
if (!connectionId) {
|
|
35074
|
+
return {
|
|
35075
|
+
kind: "required",
|
|
35076
|
+
pendingAction: {
|
|
35077
|
+
kind: "select_connections",
|
|
35078
|
+
toolCallId: action.toolCallId,
|
|
35079
|
+
draftId: action.draftId,
|
|
35080
|
+
requirements: requirements.map((item) => item === requirement && setup ? { ...item, setup } : item)
|
|
35081
|
+
}
|
|
35082
|
+
};
|
|
35083
|
+
}
|
|
35084
|
+
resolved.push({ requirement, connectionId });
|
|
35085
|
+
}
|
|
35086
|
+
const output2 = [];
|
|
35087
|
+
for (const item of resolved) {
|
|
35088
|
+
const body = {
|
|
35089
|
+
connectorId: item.requirement.connectorId,
|
|
35090
|
+
connectionType: item.requirement.connectionType,
|
|
35091
|
+
connectionId: item.connectionId
|
|
35092
|
+
};
|
|
35093
|
+
const workspaceId = options.workspaceId ?? null;
|
|
35094
|
+
if (workspaceId === null) {
|
|
35095
|
+
await api.automationDraftConnections.upsert(action.draftId, body, requestOptions);
|
|
35096
|
+
} else {
|
|
35097
|
+
await api.workspaceAutomationDraftConnections.upsert(workspaceId, action.draftId, body, requestOptions);
|
|
35098
|
+
}
|
|
35099
|
+
output2.push({ type: "success", ...body });
|
|
35100
|
+
}
|
|
35101
|
+
return { kind: "resolved", continuation: createSelectConnectionsContinuation(action, output2) };
|
|
35102
|
+
}
|
|
35103
|
+
function assertSelectionsUnambiguous(requirements, selections) {
|
|
35104
|
+
for (const selection of selections) {
|
|
35105
|
+
if (selection.connectionType)
|
|
35106
|
+
continue;
|
|
35107
|
+
const matchingTypes = new Set(requirements.filter((requirement) => requirement.connectorId === selection.connectorId).map((requirement) => requirement.connectionType));
|
|
35108
|
+
if (matchingTypes.size > 1) {
|
|
35109
|
+
throw new ChatTurnInputError("ambiguous_selection", `Connection selection for ${selection.connectorId} is ambiguous. Specify ${selection.connectorId}:mcp or ${selection.connectorId}:trigger.`);
|
|
35110
|
+
}
|
|
35111
|
+
}
|
|
35112
|
+
}
|
|
35113
|
+
|
|
35114
|
+
// ../../packages/sdk/dist/esm/chat-turn/transport.js
|
|
35115
|
+
import { DefaultChatTransport, readUIMessageStream } from "ai";
|
|
35116
|
+
var ChatTurnTransport = class {
|
|
35117
|
+
transport;
|
|
35118
|
+
constructor({ token, baseUrl, headers, fetch: fetch2 }) {
|
|
35119
|
+
const apiRoot = `${baseUrl.replace(/\/+$/, "")}/v1`;
|
|
35120
|
+
this.transport = new DefaultChatTransport({
|
|
35121
|
+
api: `${apiRoot}/chat`,
|
|
35122
|
+
headers: {
|
|
35123
|
+
Authorization: `Bearer ${token}`,
|
|
35124
|
+
...headers
|
|
35125
|
+
},
|
|
35126
|
+
credentials: "include",
|
|
35127
|
+
fetch: fetch2,
|
|
35128
|
+
prepareSendMessagesRequest({ messages, body, api }) {
|
|
35129
|
+
const { workspaceId, ...rest } = body ?? {};
|
|
35130
|
+
return {
|
|
35131
|
+
api: workspaceId ? `${apiRoot}/workspaces/${encodeURIComponent(workspaceId)}/chat` : api,
|
|
35132
|
+
body: {
|
|
35133
|
+
...rest,
|
|
35134
|
+
message: messages.at(-1)
|
|
35135
|
+
}
|
|
35136
|
+
};
|
|
35137
|
+
}
|
|
35138
|
+
});
|
|
35139
|
+
}
|
|
35140
|
+
/** Streams one server turn, reporting incremental text and deduplicated tool state changes. */
|
|
35141
|
+
async streamTurn({ conversationId, workspaceId = null, message, signal, onText, onToolActivity }) {
|
|
35142
|
+
const stream = await this.transport.sendMessages({
|
|
35143
|
+
trigger: "submit-message",
|
|
35144
|
+
chatId: conversationId,
|
|
35145
|
+
messageId: void 0,
|
|
35146
|
+
messages: [message],
|
|
35147
|
+
abortSignal: signal,
|
|
35148
|
+
body: { conversationId, workspaceId }
|
|
35149
|
+
});
|
|
35150
|
+
let finalMessage;
|
|
35151
|
+
let emittedText = "";
|
|
35152
|
+
const emittedToolStates = /* @__PURE__ */ new Set();
|
|
35153
|
+
for await (const currentMessage of readUIMessageStream({
|
|
35154
|
+
stream,
|
|
35155
|
+
terminateOnError: true
|
|
35156
|
+
})) {
|
|
35157
|
+
finalMessage = currentMessage;
|
|
35158
|
+
const visibleText = getVisibleText(currentMessage);
|
|
35159
|
+
if (visibleText.startsWith(emittedText)) {
|
|
35160
|
+
const delta = visibleText.slice(emittedText.length);
|
|
35161
|
+
if (delta)
|
|
35162
|
+
onText?.(delta);
|
|
35163
|
+
emittedText = visibleText;
|
|
35164
|
+
}
|
|
35165
|
+
for (const part of currentMessage.parts) {
|
|
35166
|
+
const activity = toToolActivity(part);
|
|
35167
|
+
if (!activity)
|
|
35168
|
+
continue;
|
|
35169
|
+
const key = `${activity.toolCallId}:${activity.state}`;
|
|
35170
|
+
if (emittedToolStates.has(key))
|
|
35171
|
+
continue;
|
|
35172
|
+
emittedToolStates.add(key);
|
|
35173
|
+
onToolActivity?.(activity);
|
|
35174
|
+
}
|
|
35175
|
+
}
|
|
35176
|
+
if (!finalMessage) {
|
|
35177
|
+
throw new Error("The Automations chat returned an empty response.");
|
|
35178
|
+
}
|
|
35179
|
+
return finalMessage;
|
|
35180
|
+
}
|
|
35181
|
+
};
|
|
35182
|
+
function toToolActivity(part) {
|
|
35183
|
+
if (!part.type.startsWith("tool-") || !("toolCallId" in part) || !("state" in part)) {
|
|
35184
|
+
return null;
|
|
35185
|
+
}
|
|
35186
|
+
return {
|
|
35187
|
+
tool: part.type.slice("tool-".length),
|
|
35188
|
+
toolCallId: String(part.toolCallId),
|
|
35189
|
+
state: String(part.state)
|
|
35190
|
+
};
|
|
35191
|
+
}
|
|
35192
|
+
|
|
34699
35193
|
// src/commands/read/format.ts
|
|
34700
35194
|
function formatAutomationList(page) {
|
|
34701
35195
|
if (page.data.length === 0) return "No automations found.";
|
|
@@ -34864,9 +35358,6 @@ function getMessageSummary(message) {
|
|
|
34864
35358
|
const partTypes = message.parts.filter(isRecord2).map((part) => typeof part.type === "string" ? part.type : "unknown");
|
|
34865
35359
|
return partTypes.length > 0 ? `[${partTypes.join(", ")}]` : "(no visible text)";
|
|
34866
35360
|
}
|
|
34867
|
-
function isTextPart(value) {
|
|
34868
|
-
return isRecord2(value) && value.type === "text" && typeof value.text === "string";
|
|
34869
|
-
}
|
|
34870
35361
|
function isRecord2(value) {
|
|
34871
35362
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
34872
35363
|
}
|
|
@@ -35245,463 +35736,6 @@ function collectOption(value, previous) {
|
|
|
35245
35736
|
return [...previous, value];
|
|
35246
35737
|
}
|
|
35247
35738
|
|
|
35248
|
-
// ../../packages/sdk/dist/esm/chat-turn/connection-requirements.js
|
|
35249
|
-
var CONNECTION_LOOKUP_CONCURRENCY = 4;
|
|
35250
|
-
function deduplicateConnectionRequirements(requirements) {
|
|
35251
|
-
const seen = /* @__PURE__ */ new Set();
|
|
35252
|
-
return requirements.filter((requirement) => {
|
|
35253
|
-
const key = JSON.stringify([requirement.connectorId, requirement.connectionType]);
|
|
35254
|
-
if (seen.has(key))
|
|
35255
|
-
return false;
|
|
35256
|
-
seen.add(key);
|
|
35257
|
-
return true;
|
|
35258
|
-
});
|
|
35259
|
-
}
|
|
35260
|
-
async function loadConnectionRequirements(connections, requirements, options) {
|
|
35261
|
-
return mapWithConcurrency(deduplicateConnectionRequirements(requirements), CONNECTION_LOOKUP_CONCURRENCY, async (requirement) => {
|
|
35262
|
-
const response = await connections.list({
|
|
35263
|
-
connectorId: requirement.connectorId,
|
|
35264
|
-
capability: requirement.connectionType,
|
|
35265
|
-
status: "authorized"
|
|
35266
|
-
}, options);
|
|
35267
|
-
return {
|
|
35268
|
-
...requirement,
|
|
35269
|
-
availableConnections: response.connections.map((connection) => ({
|
|
35270
|
-
id: connection.id,
|
|
35271
|
-
label: connection.accountDisplayLabel ?? connection.name ?? connection.id
|
|
35272
|
-
}))
|
|
35273
|
-
};
|
|
35274
|
-
});
|
|
35275
|
-
}
|
|
35276
|
-
async function mapWithConcurrency(items, concurrency, map2) {
|
|
35277
|
-
const results = new Array(items.length);
|
|
35278
|
-
let next = 0;
|
|
35279
|
-
const workers = Array.from({ length: Math.min(concurrency, items.length) }, async () => {
|
|
35280
|
-
while (next < items.length) {
|
|
35281
|
-
const index = next;
|
|
35282
|
-
next += 1;
|
|
35283
|
-
results[index] = await map2(items[index]);
|
|
35284
|
-
}
|
|
35285
|
-
});
|
|
35286
|
-
await Promise.all(workers);
|
|
35287
|
-
return results;
|
|
35288
|
-
}
|
|
35289
|
-
|
|
35290
|
-
// ../../packages/sdk/dist/esm/chat-turn/connection-setup.js
|
|
35291
|
-
async function startConnectionSetup(connections, request2, options) {
|
|
35292
|
-
const created = await connections.create({
|
|
35293
|
-
connectorId: request2.connectorId,
|
|
35294
|
-
capability: request2.capability,
|
|
35295
|
-
...request2.automationIds?.length ? { body: { automationIds: [...request2.automationIds] } } : {}
|
|
35296
|
-
}, options);
|
|
35297
|
-
return { connectionId: created.connectionId, setup: created.setup, resumed: false };
|
|
35298
|
-
}
|
|
35299
|
-
function summarizeConnectionSetup(setup) {
|
|
35300
|
-
if (setup?.kind === "oauth") {
|
|
35301
|
-
return { setupKind: "oauth", authorizationUrl: setup.authorizationUrl };
|
|
35302
|
-
}
|
|
35303
|
-
if (setup?.kind === "managed") {
|
|
35304
|
-
return {
|
|
35305
|
-
setupKind: "managed",
|
|
35306
|
-
instructions: setup.instructions,
|
|
35307
|
-
code: setup.code,
|
|
35308
|
-
deepLinkUrl: setup.deepLinkUrl,
|
|
35309
|
-
expiresAt: setup.expiresAt
|
|
35310
|
-
};
|
|
35311
|
-
}
|
|
35312
|
-
return { setupKind: "none" };
|
|
35313
|
-
}
|
|
35314
|
-
function getConnectionSetupUrl(setup) {
|
|
35315
|
-
if (setup?.kind === "oauth")
|
|
35316
|
-
return setup.authorizationUrl;
|
|
35317
|
-
if (setup?.kind === "managed")
|
|
35318
|
-
return setup.deepLinkUrl;
|
|
35319
|
-
return null;
|
|
35320
|
-
}
|
|
35321
|
-
|
|
35322
|
-
// ../../packages/core/dist/esm/chat-tools/client-tool-result.js
|
|
35323
|
-
var clientToolContinuationPartSchema = external_exports.discriminatedUnion("type", [
|
|
35324
|
-
toolPromptEnablePushResultSchema.omit({ input: true }).strict(),
|
|
35325
|
-
toolSelectConnectionsResultSchema.omit({ input: true }).strict()
|
|
35326
|
-
]);
|
|
35327
|
-
|
|
35328
|
-
// ../../packages/core/dist/esm/chat-tools/update-memory.js
|
|
35329
|
-
var UpdateMemoryInputSchema = external_exports.object({
|
|
35330
|
-
append: external_exports.string().min(1).optional(),
|
|
35331
|
-
replace: external_exports.object({
|
|
35332
|
-
old: external_exports.string().min(1),
|
|
35333
|
-
new: external_exports.string()
|
|
35334
|
-
}).optional()
|
|
35335
|
-
});
|
|
35336
|
-
var UpdateMemoryOutputSchema = external_exports.object({
|
|
35337
|
-
memory: external_exports.string().nullable(),
|
|
35338
|
-
// What the memory held before this write — the chat UI's Undo restores it.
|
|
35339
|
-
previousMemory: external_exports.string().nullable()
|
|
35340
|
-
});
|
|
35341
|
-
var toolUpdateMemorySchema = external_exports.object({
|
|
35342
|
-
type: external_exports.literal("tool-update-memory"),
|
|
35343
|
-
toolCallId: external_exports.string().min(1),
|
|
35344
|
-
state: external_exports.literal("input-available"),
|
|
35345
|
-
input: UpdateMemoryInputSchema
|
|
35346
|
-
});
|
|
35347
|
-
var toolUpdateMemoryResultSchema = external_exports.object({
|
|
35348
|
-
type: external_exports.literal("tool-update-memory"),
|
|
35349
|
-
toolCallId: external_exports.string().min(1),
|
|
35350
|
-
state: external_exports.literal("output-available"),
|
|
35351
|
-
input: UpdateMemoryInputSchema,
|
|
35352
|
-
output: UpdateMemoryOutputSchema
|
|
35353
|
-
});
|
|
35354
|
-
|
|
35355
|
-
// ../../packages/sdk/dist/esm/chat-turn/messages.js
|
|
35356
|
-
function createUserMessage(text2) {
|
|
35357
|
-
return {
|
|
35358
|
-
id: globalThis.crypto.randomUUID(),
|
|
35359
|
-
role: "user",
|
|
35360
|
-
parts: [{ type: "text", text: text2 }]
|
|
35361
|
-
};
|
|
35362
|
-
}
|
|
35363
|
-
function toUiMessage(message) {
|
|
35364
|
-
if (message.role !== "user" && message.role !== "assistant" && message.role !== "system") {
|
|
35365
|
-
throw new Error(`Unsupported persisted chat role: ${message.role}`);
|
|
35366
|
-
}
|
|
35367
|
-
if (!Array.isArray(message.parts)) {
|
|
35368
|
-
throw new Error(`Persisted chat message ${message.messageId} has invalid parts.`);
|
|
35369
|
-
}
|
|
35370
|
-
return {
|
|
35371
|
-
id: message.messageId,
|
|
35372
|
-
role: message.role,
|
|
35373
|
-
parts: message.parts
|
|
35374
|
-
};
|
|
35375
|
-
}
|
|
35376
|
-
function getVisibleText(message) {
|
|
35377
|
-
return message.parts.filter((part) => part.type === "text").map((part) => part.text).join("");
|
|
35378
|
-
}
|
|
35379
|
-
function getPendingClientAction(message) {
|
|
35380
|
-
for (let index = message.parts.length - 1; index >= 0; index -= 1) {
|
|
35381
|
-
const part = message.parts[index];
|
|
35382
|
-
if (isSelectConnections(part)) {
|
|
35383
|
-
return {
|
|
35384
|
-
kind: "select_connections",
|
|
35385
|
-
message,
|
|
35386
|
-
toolCallId: part.toolCallId,
|
|
35387
|
-
draftId: part.input.draftId,
|
|
35388
|
-
connections: part.input.connections
|
|
35389
|
-
};
|
|
35390
|
-
}
|
|
35391
|
-
if (isPromptEnablePush(part)) {
|
|
35392
|
-
return {
|
|
35393
|
-
kind: "enable_push",
|
|
35394
|
-
message,
|
|
35395
|
-
toolCallId: part.toolCallId,
|
|
35396
|
-
draftId: part.input.draftId
|
|
35397
|
-
};
|
|
35398
|
-
}
|
|
35399
|
-
}
|
|
35400
|
-
return null;
|
|
35401
|
-
}
|
|
35402
|
-
function getPendingActionFromMessages(messages) {
|
|
35403
|
-
const latestMessage = messages.at(-1);
|
|
35404
|
-
if (!latestMessage || latestMessage.role !== "assistant")
|
|
35405
|
-
return null;
|
|
35406
|
-
return getPendingClientAction(toUiMessage(latestMessage));
|
|
35407
|
-
}
|
|
35408
|
-
function getPublishedAutomationId(message) {
|
|
35409
|
-
for (let index = message.parts.length - 1; index >= 0; index -= 1) {
|
|
35410
|
-
const part = message.parts[index];
|
|
35411
|
-
if (isPublishDraftResult(part) && part.output.success) {
|
|
35412
|
-
return part.output.automationId;
|
|
35413
|
-
}
|
|
35414
|
-
}
|
|
35415
|
-
return void 0;
|
|
35416
|
-
}
|
|
35417
|
-
function createEnablePushContinuation(action, output2) {
|
|
35418
|
-
return {
|
|
35419
|
-
id: action.message.id,
|
|
35420
|
-
role: "assistant",
|
|
35421
|
-
parts: [
|
|
35422
|
-
{
|
|
35423
|
-
type: "tool-prompt-enable-push-notifications",
|
|
35424
|
-
toolCallId: action.toolCallId,
|
|
35425
|
-
state: "output-available",
|
|
35426
|
-
output: output2
|
|
35427
|
-
}
|
|
35428
|
-
]
|
|
35429
|
-
};
|
|
35430
|
-
}
|
|
35431
|
-
function createSelectConnectionsContinuation(action, output2) {
|
|
35432
|
-
return {
|
|
35433
|
-
id: action.message.id,
|
|
35434
|
-
role: "assistant",
|
|
35435
|
-
parts: [
|
|
35436
|
-
{
|
|
35437
|
-
type: "tool-select-connections",
|
|
35438
|
-
toolCallId: action.toolCallId,
|
|
35439
|
-
state: "output-available",
|
|
35440
|
-
output: output2
|
|
35441
|
-
}
|
|
35442
|
-
]
|
|
35443
|
-
};
|
|
35444
|
-
}
|
|
35445
|
-
|
|
35446
|
-
// ../../packages/sdk/dist/esm/chat-turn/types.js
|
|
35447
|
-
var ChatTurnInputError = class extends Error {
|
|
35448
|
-
code;
|
|
35449
|
-
constructor(code, message) {
|
|
35450
|
-
super(message);
|
|
35451
|
-
this.name = "ChatTurnInputError";
|
|
35452
|
-
this.code = code;
|
|
35453
|
-
}
|
|
35454
|
-
};
|
|
35455
|
-
|
|
35456
|
-
// ../../packages/sdk/dist/esm/chat-turn/run-conversation-turn.js
|
|
35457
|
-
async function runConversationTurn(options) {
|
|
35458
|
-
const { api, transport, conversationId, signal } = options;
|
|
35459
|
-
const workspaceId = options.workspaceId ?? null;
|
|
35460
|
-
const requestOptions = { signal };
|
|
35461
|
-
const pending = await readPendingAction(options);
|
|
35462
|
-
let nextMessage;
|
|
35463
|
-
if (pending?.kind === "enable_push") {
|
|
35464
|
-
if ("message" in options.input || options.input.selections.length > 0) {
|
|
35465
|
-
throw new ChatTurnInputError("awaiting_push", "The conversation is waiting for the push notification prompt to be answered.");
|
|
35466
|
-
}
|
|
35467
|
-
nextMessage = await answerEnablePush(options, pending);
|
|
35468
|
-
} else if ("message" in options.input) {
|
|
35469
|
-
if (pending?.kind === "select_connections") {
|
|
35470
|
-
throw new ChatTurnInputError("awaiting_selection", "The conversation is waiting for connection selection.");
|
|
35471
|
-
}
|
|
35472
|
-
nextMessage = createUserMessage(options.input.message);
|
|
35473
|
-
} else {
|
|
35474
|
-
const selections = options.input.selections;
|
|
35475
|
-
if (pending?.kind !== "select_connections") {
|
|
35476
|
-
throw new ChatTurnInputError(selections.length > 0 ? "not_awaiting_selection" : "input_required", selections.length > 0 ? "The conversation is not waiting for connection selection." : "A message is required to continue.");
|
|
35477
|
-
}
|
|
35478
|
-
const resolution = await resolveSelectConnections(options, pending, selections);
|
|
35479
|
-
if (resolution.kind === "required") {
|
|
35480
|
-
return actionRequired(conversationId, getVisibleText(pending.message), resolution.pendingAction);
|
|
35481
|
-
}
|
|
35482
|
-
nextMessage = resolution.continuation;
|
|
35483
|
-
}
|
|
35484
|
-
while (true) {
|
|
35485
|
-
const response = await transport.streamTurn({
|
|
35486
|
-
conversationId,
|
|
35487
|
-
workspaceId,
|
|
35488
|
-
message: nextMessage,
|
|
35489
|
-
signal,
|
|
35490
|
-
onText: options.onText,
|
|
35491
|
-
onToolActivity: options.onToolActivity
|
|
35492
|
-
});
|
|
35493
|
-
const assistantText = getVisibleText(response);
|
|
35494
|
-
const automationId = getPublishedAutomationId(response);
|
|
35495
|
-
if (automationId) {
|
|
35496
|
-
options.onPublished?.(automationId);
|
|
35497
|
-
const archive = await archiveConversation(api, conversationId, requestOptions);
|
|
35498
|
-
return {
|
|
35499
|
-
conversationId,
|
|
35500
|
-
outcome: "published",
|
|
35501
|
-
assistantText,
|
|
35502
|
-
automationId,
|
|
35503
|
-
...archive
|
|
35504
|
-
};
|
|
35505
|
-
}
|
|
35506
|
-
const responseAction = getPendingClientAction(response);
|
|
35507
|
-
if (responseAction?.kind === "select_connections") {
|
|
35508
|
-
const resolution = await resolveSelectConnections(options, responseAction, []);
|
|
35509
|
-
if (resolution.kind === "resolved") {
|
|
35510
|
-
nextMessage = resolution.continuation;
|
|
35511
|
-
continue;
|
|
35512
|
-
}
|
|
35513
|
-
return actionRequired(conversationId, assistantText, resolution.pendingAction);
|
|
35514
|
-
}
|
|
35515
|
-
if (responseAction?.kind === "enable_push") {
|
|
35516
|
-
return actionRequired(conversationId, assistantText, {
|
|
35517
|
-
kind: "enable_push",
|
|
35518
|
-
toolCallId: responseAction.toolCallId,
|
|
35519
|
-
draftId: responseAction.draftId
|
|
35520
|
-
});
|
|
35521
|
-
}
|
|
35522
|
-
return { conversationId, outcome: "awaiting_input", assistantText };
|
|
35523
|
-
}
|
|
35524
|
-
}
|
|
35525
|
-
async function answerEnablePush(options, action) {
|
|
35526
|
-
const { subscriptions } = await options.api.notifications.push.list({
|
|
35527
|
-
signal: options.signal
|
|
35528
|
-
});
|
|
35529
|
-
const deviceCount = subscriptions.length;
|
|
35530
|
-
return createEnablePushContinuation(action, {
|
|
35531
|
-
enabled: deviceCount > 0,
|
|
35532
|
-
deviceCount,
|
|
35533
|
-
message: deviceCount > 0 ? `Push notifications are enabled on ${deviceCount} device${deviceCount === 1 ? "" : "s"}.` : "The user has not enabled push notifications."
|
|
35534
|
-
});
|
|
35535
|
-
}
|
|
35536
|
-
async function readPendingAction(options) {
|
|
35537
|
-
if (options.pendingAction !== void 0)
|
|
35538
|
-
return options.pendingAction;
|
|
35539
|
-
const messages = await options.api.chat.getMessages(options.conversationId, {
|
|
35540
|
-
signal: options.signal
|
|
35541
|
-
});
|
|
35542
|
-
return getPendingActionFromMessages(messages);
|
|
35543
|
-
}
|
|
35544
|
-
function actionRequired(conversationId, assistantText, pendingAction) {
|
|
35545
|
-
return { conversationId, outcome: "action_required", assistantText, pendingAction };
|
|
35546
|
-
}
|
|
35547
|
-
async function archiveConversation(api, conversationId, requestOptions) {
|
|
35548
|
-
try {
|
|
35549
|
-
const conversation = await api.chat.updateConversation(conversationId, { isArchived: true }, requestOptions);
|
|
35550
|
-
if (!conversation.isArchived) {
|
|
35551
|
-
throw new Error("The Automations API returned an active conversation.");
|
|
35552
|
-
}
|
|
35553
|
-
return { conversationArchived: true };
|
|
35554
|
-
} catch (error62) {
|
|
35555
|
-
return {
|
|
35556
|
-
conversationArchived: false,
|
|
35557
|
-
conversationArchiveError: error62 instanceof Error ? error62.message : String(error62)
|
|
35558
|
-
};
|
|
35559
|
-
}
|
|
35560
|
-
}
|
|
35561
|
-
async function resolveSelectConnections(options, action, selections) {
|
|
35562
|
-
const { api, signal } = options;
|
|
35563
|
-
const requestOptions = { signal };
|
|
35564
|
-
const requirements = await loadConnectionRequirements(api.connections, action.connections, requestOptions);
|
|
35565
|
-
assertSelectionsUnambiguous(requirements, selections);
|
|
35566
|
-
const resolved = [];
|
|
35567
|
-
for (const requirement of requirements) {
|
|
35568
|
-
const explicit = selections.find((selection) => selection.connectorId === requirement.connectorId && (!selection.connectionType || selection.connectionType === requirement.connectionType));
|
|
35569
|
-
let connectionId = explicit?.connectionId;
|
|
35570
|
-
let setup;
|
|
35571
|
-
if (connectionId) {
|
|
35572
|
-
const exists = requirement.availableConnections.some((connection) => connection.id === connectionId);
|
|
35573
|
-
if (!exists) {
|
|
35574
|
-
throw new ChatTurnInputError("unknown_connection", `Connection ${connectionId} is not an authorized ${requirement.serviceName} connection.`);
|
|
35575
|
-
}
|
|
35576
|
-
} else if (requirement.availableConnections.length === 1) {
|
|
35577
|
-
connectionId = requirement.availableConnections[0]?.id;
|
|
35578
|
-
} else if (requirement.availableConnections.length > 1) {
|
|
35579
|
-
connectionId = await options.chooseConnection?.(requirement);
|
|
35580
|
-
} else if (options.authorizeConnection) {
|
|
35581
|
-
connectionId = await options.authorizeConnection(requirement);
|
|
35582
|
-
} else {
|
|
35583
|
-
setup = await startConnectionSetup(api.connections, { connectorId: requirement.connectorId, capability: requirement.connectionType }, requestOptions);
|
|
35584
|
-
}
|
|
35585
|
-
if (!connectionId) {
|
|
35586
|
-
return {
|
|
35587
|
-
kind: "required",
|
|
35588
|
-
pendingAction: {
|
|
35589
|
-
kind: "select_connections",
|
|
35590
|
-
toolCallId: action.toolCallId,
|
|
35591
|
-
draftId: action.draftId,
|
|
35592
|
-
requirements: requirements.map((item) => item === requirement && setup ? { ...item, setup } : item)
|
|
35593
|
-
}
|
|
35594
|
-
};
|
|
35595
|
-
}
|
|
35596
|
-
resolved.push({ requirement, connectionId });
|
|
35597
|
-
}
|
|
35598
|
-
const output2 = [];
|
|
35599
|
-
for (const item of resolved) {
|
|
35600
|
-
const body = {
|
|
35601
|
-
connectorId: item.requirement.connectorId,
|
|
35602
|
-
connectionType: item.requirement.connectionType,
|
|
35603
|
-
connectionId: item.connectionId
|
|
35604
|
-
};
|
|
35605
|
-
const workspaceId = options.workspaceId ?? null;
|
|
35606
|
-
if (workspaceId === null) {
|
|
35607
|
-
await api.automationDraftConnections.upsert(action.draftId, body, requestOptions);
|
|
35608
|
-
} else {
|
|
35609
|
-
await api.workspaceAutomationDraftConnections.upsert(workspaceId, action.draftId, body, requestOptions);
|
|
35610
|
-
}
|
|
35611
|
-
output2.push({ type: "success", ...body });
|
|
35612
|
-
}
|
|
35613
|
-
return { kind: "resolved", continuation: createSelectConnectionsContinuation(action, output2) };
|
|
35614
|
-
}
|
|
35615
|
-
function assertSelectionsUnambiguous(requirements, selections) {
|
|
35616
|
-
for (const selection of selections) {
|
|
35617
|
-
if (selection.connectionType)
|
|
35618
|
-
continue;
|
|
35619
|
-
const matchingTypes = new Set(requirements.filter((requirement) => requirement.connectorId === selection.connectorId).map((requirement) => requirement.connectionType));
|
|
35620
|
-
if (matchingTypes.size > 1) {
|
|
35621
|
-
throw new ChatTurnInputError("ambiguous_selection", `Connection selection for ${selection.connectorId} is ambiguous. Specify ${selection.connectorId}:mcp or ${selection.connectorId}:trigger.`);
|
|
35622
|
-
}
|
|
35623
|
-
}
|
|
35624
|
-
}
|
|
35625
|
-
|
|
35626
|
-
// ../../packages/sdk/dist/esm/chat-turn/transport.js
|
|
35627
|
-
import { DefaultChatTransport, readUIMessageStream } from "ai";
|
|
35628
|
-
var ChatTurnTransport = class {
|
|
35629
|
-
transport;
|
|
35630
|
-
constructor({ token, baseUrl, headers, fetch: fetch2 }) {
|
|
35631
|
-
const apiRoot = `${baseUrl.replace(/\/+$/, "")}/v1`;
|
|
35632
|
-
this.transport = new DefaultChatTransport({
|
|
35633
|
-
api: `${apiRoot}/chat`,
|
|
35634
|
-
headers: {
|
|
35635
|
-
Authorization: `Bearer ${token}`,
|
|
35636
|
-
...headers
|
|
35637
|
-
},
|
|
35638
|
-
credentials: "include",
|
|
35639
|
-
fetch: fetch2,
|
|
35640
|
-
prepareSendMessagesRequest({ messages, body, api }) {
|
|
35641
|
-
const { workspaceId, ...rest } = body ?? {};
|
|
35642
|
-
return {
|
|
35643
|
-
api: workspaceId ? `${apiRoot}/workspaces/${encodeURIComponent(workspaceId)}/chat` : api,
|
|
35644
|
-
body: {
|
|
35645
|
-
...rest,
|
|
35646
|
-
message: messages.at(-1)
|
|
35647
|
-
}
|
|
35648
|
-
};
|
|
35649
|
-
}
|
|
35650
|
-
});
|
|
35651
|
-
}
|
|
35652
|
-
/** Streams one server turn, reporting incremental text and deduplicated tool state changes. */
|
|
35653
|
-
async streamTurn({ conversationId, workspaceId = null, message, signal, onText, onToolActivity }) {
|
|
35654
|
-
const stream = await this.transport.sendMessages({
|
|
35655
|
-
trigger: "submit-message",
|
|
35656
|
-
chatId: conversationId,
|
|
35657
|
-
messageId: void 0,
|
|
35658
|
-
messages: [message],
|
|
35659
|
-
abortSignal: signal,
|
|
35660
|
-
body: { conversationId, workspaceId }
|
|
35661
|
-
});
|
|
35662
|
-
let finalMessage;
|
|
35663
|
-
let emittedText = "";
|
|
35664
|
-
const emittedToolStates = /* @__PURE__ */ new Set();
|
|
35665
|
-
for await (const currentMessage of readUIMessageStream({
|
|
35666
|
-
stream,
|
|
35667
|
-
terminateOnError: true
|
|
35668
|
-
})) {
|
|
35669
|
-
finalMessage = currentMessage;
|
|
35670
|
-
const visibleText = getVisibleText(currentMessage);
|
|
35671
|
-
if (visibleText.startsWith(emittedText)) {
|
|
35672
|
-
const delta = visibleText.slice(emittedText.length);
|
|
35673
|
-
if (delta)
|
|
35674
|
-
onText?.(delta);
|
|
35675
|
-
emittedText = visibleText;
|
|
35676
|
-
}
|
|
35677
|
-
for (const part of currentMessage.parts) {
|
|
35678
|
-
const activity = toToolActivity(part);
|
|
35679
|
-
if (!activity)
|
|
35680
|
-
continue;
|
|
35681
|
-
const key = `${activity.toolCallId}:${activity.state}`;
|
|
35682
|
-
if (emittedToolStates.has(key))
|
|
35683
|
-
continue;
|
|
35684
|
-
emittedToolStates.add(key);
|
|
35685
|
-
onToolActivity?.(activity);
|
|
35686
|
-
}
|
|
35687
|
-
}
|
|
35688
|
-
if (!finalMessage) {
|
|
35689
|
-
throw new Error("The Automations chat returned an empty response.");
|
|
35690
|
-
}
|
|
35691
|
-
return finalMessage;
|
|
35692
|
-
}
|
|
35693
|
-
};
|
|
35694
|
-
function toToolActivity(part) {
|
|
35695
|
-
if (!part.type.startsWith("tool-") || !("toolCallId" in part) || !("state" in part)) {
|
|
35696
|
-
return null;
|
|
35697
|
-
}
|
|
35698
|
-
return {
|
|
35699
|
-
tool: part.type.slice("tool-".length),
|
|
35700
|
-
toolCallId: String(part.toolCallId),
|
|
35701
|
-
state: String(part.state)
|
|
35702
|
-
};
|
|
35703
|
-
}
|
|
35704
|
-
|
|
35705
35739
|
// src/commands/chat/chat-service.ts
|
|
35706
35740
|
import { createInterface } from "node:readline/promises";
|
|
35707
35741
|
|