@capybara-hq/kernel 0.1.0-rc.2 → 0.1.0-rc.4
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/admin/admin.controller.d.ts +9 -4
- package/dist/admin/admin.controller.js +13 -4
- package/dist/admin/extensions.controller.d.ts +8 -1
- package/dist/admin/extensions.controller.js +22 -2
- package/dist/agents/agent-lookup.d.ts +3 -0
- package/dist/agents/agent-lookup.js +20 -2
- package/dist/agents/agent-profile.service.d.ts +29 -0
- package/dist/agents/agent-profile.service.js +117 -0
- package/dist/agents/agents.controller.d.ts +93 -3
- package/dist/agents/agents.controller.js +114 -4
- package/dist/agents/agents.module.js +6 -2
- package/dist/agents/agents.service.d.ts +13 -5
- package/dist/agents/agents.service.js +49 -13
- package/dist/agents/definition.d.ts +35 -8
- package/dist/agents/definition.js +203 -17
- package/dist/agents/instruction-files.d.ts +60 -0
- package/dist/agents/instruction-files.js +111 -0
- package/dist/agents/models.controller.d.ts +9 -3
- package/dist/agents/models.controller.js +19 -4
- package/dist/agents/profile.d.ts +96 -0
- package/dist/agents/profile.js +51 -0
- package/dist/agents/readiness.controller.d.ts +26 -0
- package/dist/agents/readiness.controller.js +56 -0
- package/dist/agents/templates.js +20 -5
- package/dist/background/background.controller.d.ts +38 -0
- package/dist/background/background.controller.js +87 -0
- package/dist/background/background.module.d.ts +10 -0
- package/dist/background/background.module.js +32 -0
- package/dist/background/finish.d.ts +43 -0
- package/dist/background/finish.js +94 -0
- package/dist/background/launch-lock.d.ts +14 -0
- package/dist/background/launch-lock.js +39 -0
- package/dist/background/launch.d.ts +36 -0
- package/dist/background/launch.js +70 -0
- package/dist/background/poll.job.d.ts +53 -0
- package/dist/background/poll.job.js +182 -0
- package/dist/background/render.d.ts +23 -0
- package/dist/background/render.js +48 -0
- package/dist/background/session.d.ts +37 -0
- package/dist/background/session.js +66 -0
- package/dist/background/status.d.ts +35 -0
- package/dist/background/status.js +57 -0
- package/dist/background/stop.d.ts +62 -0
- package/dist/background/stop.js +225 -0
- package/dist/background/store.d.ts +150 -0
- package/dist/background/store.js +351 -0
- package/dist/background/store.module.d.ts +6 -0
- package/dist/background/store.module.js +22 -0
- package/dist/background/tasks.service.d.ts +67 -0
- package/dist/background/tasks.service.js +186 -0
- package/dist/background/wake-rules.d.ts +57 -0
- package/dist/background/wake-rules.js +83 -0
- package/dist/background/wake.d.ts +28 -0
- package/dist/background/wake.js +57 -0
- package/dist/catalog/catalog-content.js +4 -1
- package/dist/catalog/claude/agents.js +15 -10
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/plugin-import.js +1 -1
- package/dist/catalog/plugin-upgrade.js +1 -1
- package/dist/channels/cards.d.ts +8 -2
- package/dist/channels/cards.js +17 -9
- package/dist/channels/connections.service.d.ts +16 -1
- package/dist/channels/connections.service.js +38 -4
- package/dist/channels/threads.d.ts +5 -0
- package/dist/channels/threads.js +8 -0
- package/dist/config/schema.d.ts +18 -0
- package/dist/config/schema.js +104 -2
- package/dist/conversations/access.js +2 -0
- package/dist/conversations/artifacts.d.ts +1 -1
- package/dist/conversations/artifacts.js +1 -1
- package/dist/conversations/attachments.service.d.ts +30 -0
- package/dist/conversations/attachments.service.js +130 -5
- package/dist/conversations/conversations.controller.d.ts +36 -5
- package/dist/conversations/conversations.controller.js +62 -12
- package/dist/conversations/conversations.module.js +3 -0
- package/dist/conversations/conversations.service.d.ts +44 -2
- package/dist/conversations/conversations.service.js +140 -12
- package/dist/conversations/event-log.d.ts +12 -1
- package/dist/conversations/event-log.js +29 -1
- package/dist/conversations/events.d.ts +81 -3
- package/dist/conversations/events.js +83 -16
- package/dist/conversations/queue.d.ts +3 -1
- package/dist/conversations/queue.js +13 -2
- package/dist/conversations/queue.service.js +3 -1
- package/dist/conversations/titles.d.ts +7 -0
- package/dist/conversations/titles.js +15 -0
- package/dist/db/kernel-schema.d.ts +60 -4
- package/dist/db/pool.d.ts +5 -0
- package/dist/db/pool.js +3 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +8 -0
- package/dist/evals/recorded-tools.d.ts +27 -1
- package/dist/evals/recorded-tools.js +85 -10
- package/dist/evals/run-replay.d.ts +10 -2
- package/dist/evals/run-replay.js +49 -12
- package/dist/evals/step-replay.js +12 -6
- package/dist/evals/trajectory.d.ts +2 -2
- package/dist/evals/trajectory.js +1 -1
- package/dist/extensions/admin-ops.js +2 -0
- package/dist/extensions/admin-view.d.ts +3 -1
- package/dist/extensions/admin-view.js +10 -2
- package/dist/extensions/blobs.js +1 -0
- package/dist/extensions/config-issues.d.ts +13 -1
- package/dist/extensions/config-issues.js +22 -5
- package/dist/extensions/config-json-schema.d.ts +43 -7
- package/dist/extensions/config-json-schema.js +124 -58
- package/dist/extensions/deployment-config-store.d.ts +6 -0
- package/dist/extensions/deployment-config.d.ts +50 -3
- package/dist/extensions/deployment-config.js +125 -28
- package/dist/extensions/display-name.d.ts +22 -0
- package/dist/extensions/display-name.js +77 -0
- package/dist/extensions/extensions.module.js +6 -0
- package/dist/extensions/host.d.ts +26 -1
- package/dist/extensions/host.js +82 -9
- package/dist/extensions/org-config.controller.d.ts +11 -3
- package/dist/extensions/org-config.controller.js +14 -6
- package/dist/extensions/org-config.d.ts +6 -0
- package/dist/extensions/org-config.js +12 -13
- package/dist/extensions/package.d.ts +14 -1
- package/dist/extensions/package.js +51 -2
- package/dist/extensions/permission-view.d.ts +3 -0
- package/dist/extensions/point-defaults.controller.d.ts +34 -0
- package/dist/extensions/point-defaults.controller.js +71 -0
- package/dist/extensions/point-defaults.d.ts +64 -0
- package/dist/extensions/point-defaults.js +206 -0
- package/dist/extensions/registry.d.ts +1 -1
- package/dist/extensions/registry.js +2 -0
- package/dist/http/api.module.js +8 -0
- package/dist/http/nest-logger.d.ts +6 -5
- package/dist/http/nest-logger.js +24 -10
- package/dist/identity/auth.controller.js +9 -5
- package/dist/identity/cookies.d.ts +20 -5
- package/dist/identity/cookies.js +44 -6
- package/dist/identity/me.controller.d.ts +5 -1
- package/dist/identity/me.controller.js +12 -3
- package/dist/identity/sessions.d.ts +12 -0
- package/dist/identity/sessions.js +45 -0
- package/dist/identity/settings.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/infra/config/kernel-config.service.js +6 -0
- package/dist/infra/database/database.module.js +1 -0
- package/dist/infra/events/kernel-events.d.ts +8 -0
- package/dist/infra/lifecycle/process-guards.js +4 -0
- package/dist/infra/logging/logging.module.d.ts +4 -2
- package/dist/infra/logging/logging.module.js +24 -6
- package/dist/infra/queue/redis-connection.d.ts +6 -0
- package/dist/infra/queue/redis-connection.js +7 -0
- package/dist/infra/redis/redis.module.js +6 -2
- package/dist/infra/tokens.d.ts +6 -1
- package/dist/infra/tokens.js +6 -1
- package/dist/lifecycle/kernel-lifecycle.js +5 -0
- package/dist/log.d.ts +13 -1
- package/dist/log.js +93 -17
- package/dist/models/purposes.d.ts +23 -0
- package/dist/models/purposes.js +31 -10
- package/dist/orgs/offboarding.d.ts +3 -1
- package/dist/orgs/offboarding.js +26 -16
- package/dist/orgs/settings.service.d.ts +7 -2
- package/dist/orgs/settings.service.js +15 -4
- package/dist/roles/worker.module.js +6 -0
- package/dist/runtime/context/build.d.ts +15 -13
- package/dist/runtime/context/build.js +45 -27
- package/dist/runtime/context/claude-tools.d.ts +3 -1
- package/dist/runtime/context/claude-tools.js +12 -12
- package/dist/runtime/context/compaction.js +4 -0
- package/dist/runtime/context/legacy-text.d.ts +22 -0
- package/dist/runtime/context/legacy-text.js +37 -0
- package/dist/runtime/context/skills.d.ts +29 -11
- package/dist/runtime/context/skills.js +37 -30
- package/dist/runtime/langgraph-loop.js +3 -2
- package/dist/runtime/loop.d.ts +5 -4
- package/dist/runtime/maintenance.d.ts +4 -2
- package/dist/runtime/maintenance.js +17 -5
- package/dist/runtime/model-call.d.ts +17 -1
- package/dist/runtime/model-call.js +4 -3
- package/dist/runtime/providers.d.ts +6 -0
- package/dist/runtime/providers.js +8 -0
- package/dist/runtime/run-finish.d.ts +1 -1
- package/dist/runtime/run-queue.d.ts +28 -5
- package/dist/runtime/run-queue.js +131 -35
- package/dist/runtime/run-worker.d.ts +2 -2
- package/dist/runtime/run-worker.js +20 -7
- package/dist/runtime/runtime.module.js +8 -3
- package/dist/runtime/step-log.d.ts +6 -0
- package/dist/runtime/step-log.js +16 -2
- package/dist/runtime/subagents/definition.d.ts +1 -6
- package/dist/runtime/subagents/definition.js +14 -13
- package/dist/runtime/subagents/dispatch.d.ts +2 -2
- package/dist/runtime/subagents/dispatch.js +2 -2
- package/dist/runtime/subagents/org-agents.js +2 -1
- package/dist/runtime/subagents/roster.d.ts +1 -1
- package/dist/runtime/subagents/roster.js +1 -1
- package/dist/runtime/subagents/skill-fork.d.ts +2 -2
- package/dist/runtime/subagents/skill-fork.js +2 -2
- package/dist/runtime/subagents/subagents.service.d.ts +3 -3
- package/dist/runtime/subagents/subagents.service.js +3 -3
- package/dist/runtime/usage-report.d.ts +2 -1
- package/dist/runtime/usage-report.js +2 -1
- package/dist/runtime/waits.d.ts +13 -7
- package/dist/runtime/waits.js +42 -16
- package/dist/sandbox/sandbox.module.js +6 -1
- package/dist/sandbox/sandbox.service.d.ts +61 -3
- package/dist/sandbox/sandbox.service.js +141 -7
- package/dist/skills/catalog.d.ts +4 -4
- package/dist/skills/catalog.js +4 -4
- package/dist/skills/changes.service.d.ts +2 -2
- package/dist/skills/changes.service.js +5 -4
- package/dist/skills/invocation-keys.d.ts +1 -1
- package/dist/skills/invocation-keys.js +1 -1
- package/dist/skills/invoke.d.ts +1 -1
- package/dist/skills/invoke.js +5 -4
- package/dist/tools/approvals.service.d.ts +6 -0
- package/dist/tools/approvals.service.js +21 -1
- package/dist/tools/builtin-names.d.ts +91 -0
- package/dist/tools/builtin-names.js +143 -0
- package/dist/tools/builtins/agent.d.ts +7 -7
- package/dist/tools/builtins/agent.js +7 -11
- package/dist/tools/builtins/ask-user.d.ts +1 -1
- package/dist/tools/builtins/ask-user.js +2 -2
- package/dist/tools/builtins/builtin-tools.d.ts +17 -3
- package/dist/tools/builtins/builtin-tools.js +36 -4
- package/dist/tools/builtins/read-tool-output.d.ts +1 -1
- package/dist/tools/builtins/read-tool-output.js +2 -2
- package/dist/tools/builtins/sandbox/bash.d.ts +4 -4
- package/dist/tools/builtins/sandbox/bash.js +259 -29
- package/dist/tools/builtins/sandbox/common.d.ts +30 -7
- package/dist/tools/builtins/sandbox/common.js +9 -5
- package/dist/tools/builtins/sandbox/deliver.d.ts +1 -1
- package/dist/tools/builtins/sandbox/deliver.js +12 -12
- package/dist/tools/builtins/sandbox/edit.d.ts +1 -1
- package/dist/tools/builtins/sandbox/edit.js +41 -30
- package/dist/tools/builtins/sandbox/file-state.d.ts +34 -0
- package/dist/tools/builtins/sandbox/file-state.js +34 -0
- package/dist/tools/builtins/sandbox/glob-match.d.ts +1 -1
- package/dist/tools/builtins/sandbox/glob-match.js +1 -1
- package/dist/tools/builtins/sandbox/glob.d.ts +1 -1
- package/dist/tools/builtins/sandbox/glob.js +4 -4
- package/dist/tools/builtins/sandbox/grep.d.ts +7 -4
- package/dist/tools/builtins/sandbox/grep.js +147 -30
- package/dist/tools/builtins/sandbox/index.d.ts +3 -1
- package/dist/tools/builtins/sandbox/index.js +7 -1
- package/dist/tools/builtins/sandbox/read.d.ts +2 -2
- package/dist/tools/builtins/sandbox/read.js +21 -14
- package/dist/tools/builtins/sandbox/task-output.d.ts +63 -0
- package/dist/tools/builtins/sandbox/task-output.js +304 -0
- package/dist/tools/builtins/sandbox/task-stop.d.ts +10 -0
- package/dist/tools/builtins/sandbox/task-stop.js +112 -0
- package/dist/tools/builtins/sandbox/write.d.ts +1 -1
- package/dist/tools/builtins/sandbox/write.js +37 -33
- package/dist/tools/builtins/skill-load.d.ts +3 -3
- package/dist/tools/builtins/skill-load.js +32 -16
- package/dist/tools/builtins/skill-write.d.ts +4 -4
- package/dist/tools/builtins/skill-write.js +10 -10
- package/dist/tools/builtins/tool-search.d.ts +13 -9
- package/dist/tools/builtins/tool-search.js +25 -14
- package/dist/tools/builtins/web/errors.d.ts +8 -0
- package/dist/tools/builtins/web/errors.js +53 -0
- package/dist/tools/builtins/web/extract.d.ts +62 -0
- package/dist/tools/builtins/web/extract.js +267 -0
- package/dist/tools/builtins/web/fetch.d.ts +55 -0
- package/dist/tools/builtins/web/fetch.js +174 -0
- package/dist/tools/builtins/web/index.d.ts +13 -0
- package/dist/tools/builtins/web/index.js +12 -0
- package/dist/tools/builtins/web/page-cache.d.ts +25 -0
- package/dist/tools/builtins/web/page-cache.js +77 -0
- package/dist/tools/builtins/web/search.d.ts +25 -0
- package/dist/tools/builtins/web/search.js +209 -0
- package/dist/tools/builtins/web/url.d.ts +17 -0
- package/dist/tools/builtins/web/url.js +43 -0
- package/dist/tools/connectors.service.js +4 -4
- package/dist/tools/display-names.d.ts +9 -0
- package/dist/tools/display-names.js +24 -0
- package/dist/tools/drift.js +5 -5
- package/dist/tools/elicitation.js +1 -1
- package/dist/tools/info.d.ts +20 -4
- package/dist/tools/info.js +55 -32
- package/dist/tools/legacy-data.d.ts +34 -0
- package/dist/tools/legacy-data.js +76 -0
- package/dist/tools/legacy-keys.d.ts +51 -0
- package/dist/tools/legacy-keys.js +115 -0
- package/dist/tools/naming.d.ts +1 -5
- package/dist/tools/naming.js +1 -7
- package/dist/tools/oauth/flow-paths.d.ts +1 -1
- package/dist/tools/oauth/flow-paths.js +1 -1
- package/dist/tools/outputs.js +1 -1
- package/dist/tools/pipeline.d.ts +13 -7
- package/dist/tools/pipeline.js +112 -39
- package/dist/tools/policy.d.ts +1 -14
- package/dist/tools/policy.js +13 -19
- package/dist/tools/questions.controller.d.ts +1 -1
- package/dist/tools/questions.controller.js +1 -1
- package/dist/tools/questions.service.d.ts +1 -1
- package/dist/tools/registry.d.ts +38 -24
- package/dist/tools/registry.js +54 -47
- package/dist/tools/resources.d.ts +1 -1
- package/dist/tools/resources.js +1 -1
- package/dist/tools/tools.module.js +13 -1
- package/dist/tools/validate.js +1 -1
- package/package.json +3 -3
- package/src/migrations/0063_tool_keys_claude_code.sql +220 -0
- package/src/migrations/0064_account_last_org.sql +7 -0
- package/src/migrations/0065_conversation_archive.sql +8 -0
- package/src/migrations/0066_extension_display_name.sql +4 -0
- package/src/migrations/0067_agent_profiles.sql +20 -0
- package/src/migrations/0068_agent_avatar_uploads.sql +7 -0
- package/src/migrations/0069_attachments_agent_idx.sql +3 -0
- package/src/migrations/0070_background_tasks.sql +37 -0
- package/src/migrations/0071_background_tasks_reserve.sql +6 -0
- package/src/migrations/0072_background_tasks_stopping.sql +5 -0
- package/src/migrations/0073_org_extension_point_defaults.sql +11 -0
- package/dist/tools/builtins/sandbox/names.d.ts +0 -7
- package/dist/tools/builtins/sandbox/names.js +0 -20
package/dist/config/schema.js
CHANGED
|
@@ -179,6 +179,14 @@ export const KernelConfigSchema = z.object({
|
|
|
179
179
|
.positive()
|
|
180
180
|
.default(5000)
|
|
181
181
|
.meta(meta({ description: "PostgreSQL connect timeout in milliseconds" })),
|
|
182
|
+
idleTimeoutMs: z
|
|
183
|
+
.number()
|
|
184
|
+
.int()
|
|
185
|
+
.positive()
|
|
186
|
+
.default(60_000)
|
|
187
|
+
.meta(meta({
|
|
188
|
+
description: "How long an idle PostgreSQL connection stays in the pool, in milliseconds",
|
|
189
|
+
})),
|
|
182
190
|
})
|
|
183
191
|
.prefault({}),
|
|
184
192
|
redis: z
|
|
@@ -568,6 +576,12 @@ export const KernelConfigSchema = z.object({
|
|
|
568
576
|
.positive()
|
|
569
577
|
.default(50)
|
|
570
578
|
.meta(meta({ description: "Maximum model steps per agent run before the final wrap-up" })),
|
|
579
|
+
wakeOnBackgroundTask: z
|
|
580
|
+
.boolean()
|
|
581
|
+
.default(true)
|
|
582
|
+
.meta(meta({
|
|
583
|
+
description: "Whether the finish of a background Bash task starts a run on an idle conversation (the person who started the task's run is the trigger); an organization can override it in its settings. When false the event is only logged and shown, and the next message picks it up",
|
|
584
|
+
})),
|
|
571
585
|
maxRunSeconds: z
|
|
572
586
|
.number()
|
|
573
587
|
.int()
|
|
@@ -656,6 +670,7 @@ export const KernelConfigSchema = z.object({
|
|
|
656
670
|
})
|
|
657
671
|
.default({
|
|
658
672
|
maxSteps: 50,
|
|
673
|
+
wakeOnBackgroundTask: true,
|
|
659
674
|
maxRunSeconds: DEFAULT_MAX_RUN_SECONDS,
|
|
660
675
|
streamIdleMs: 60000,
|
|
661
676
|
maxOutputTokens: 16000,
|
|
@@ -751,7 +766,7 @@ export const KernelConfigSchema = z.object({
|
|
|
751
766
|
.int()
|
|
752
767
|
.positive()
|
|
753
768
|
.default(20000)
|
|
754
|
-
.meta(meta({ description: "Maximum characters returned by one
|
|
769
|
+
.meta(meta({ description: "Maximum characters returned by one ReadToolOutput call" })),
|
|
755
770
|
oauthAllowInsecureLoopback: z
|
|
756
771
|
.boolean()
|
|
757
772
|
.default(false)
|
|
@@ -946,6 +961,64 @@ export const KernelConfigSchema = z.object({
|
|
|
946
961
|
})),
|
|
947
962
|
})
|
|
948
963
|
.prefault({}),
|
|
964
|
+
web: z
|
|
965
|
+
.object({
|
|
966
|
+
search: z
|
|
967
|
+
.object({
|
|
968
|
+
maxResults: z
|
|
969
|
+
.number()
|
|
970
|
+
.int()
|
|
971
|
+
.min(1)
|
|
972
|
+
.max(20)
|
|
973
|
+
.default(10)
|
|
974
|
+
.meta(meta({
|
|
975
|
+
hot: true,
|
|
976
|
+
description: "Maximum number of results one WebSearch call returns to the model, however many the search provider returns",
|
|
977
|
+
})),
|
|
978
|
+
})
|
|
979
|
+
.prefault({}),
|
|
980
|
+
fetch: z
|
|
981
|
+
.object({
|
|
982
|
+
maxPageChars: z
|
|
983
|
+
.number()
|
|
984
|
+
.int()
|
|
985
|
+
.positive()
|
|
986
|
+
.default(400_000)
|
|
987
|
+
.meta(meta({
|
|
988
|
+
hot: true,
|
|
989
|
+
description: "Maximum characters of a fetched page kept for answering a WebFetch prompt; longer pages are truncated",
|
|
990
|
+
})),
|
|
991
|
+
maxAnswerTokens: z
|
|
992
|
+
.number()
|
|
993
|
+
.int()
|
|
994
|
+
.positive()
|
|
995
|
+
.default(4000)
|
|
996
|
+
.meta(meta({
|
|
997
|
+
hot: true,
|
|
998
|
+
description: "Maximum output tokens of the model call that answers a WebFetch prompt from the page",
|
|
999
|
+
})),
|
|
1000
|
+
cacheSeconds: z
|
|
1001
|
+
.number()
|
|
1002
|
+
.int()
|
|
1003
|
+
.min(0)
|
|
1004
|
+
.default(900)
|
|
1005
|
+
.meta(meta({
|
|
1006
|
+
hot: true,
|
|
1007
|
+
description: "Seconds a fetched page is cached per organization and URL; 0 turns the cache off",
|
|
1008
|
+
})),
|
|
1009
|
+
timeoutMs: z
|
|
1010
|
+
.number()
|
|
1011
|
+
.int()
|
|
1012
|
+
.positive()
|
|
1013
|
+
.default(180_000)
|
|
1014
|
+
.meta(meta({
|
|
1015
|
+
hot: true,
|
|
1016
|
+
description: "Time limit of one WebFetch call in milliseconds, the provider's fetch and the answering model call together; replaces tools.timeoutMs for WebFetch",
|
|
1017
|
+
})),
|
|
1018
|
+
})
|
|
1019
|
+
.prefault({}),
|
|
1020
|
+
})
|
|
1021
|
+
.prefault({}),
|
|
949
1022
|
sandbox: z
|
|
950
1023
|
.object({
|
|
951
1024
|
image: z
|
|
@@ -978,8 +1051,37 @@ export const KernelConfigSchema = z.object({
|
|
|
978
1051
|
.positive()
|
|
979
1052
|
.default(104_857_600)
|
|
980
1053
|
.meta(meta({
|
|
981
|
-
description: "Largest file in bytes an agent may deliver from its sandbox to the user as an artifact (
|
|
1054
|
+
description: "Largest file in bytes an agent may deliver from its sandbox to the user as an artifact (Deliver)",
|
|
982
1055
|
})),
|
|
1056
|
+
background: z
|
|
1057
|
+
.object({
|
|
1058
|
+
maxTasks: z
|
|
1059
|
+
.number()
|
|
1060
|
+
.int()
|
|
1061
|
+
.min(1)
|
|
1062
|
+
.max(100)
|
|
1063
|
+
.default(4)
|
|
1064
|
+
.meta(meta({
|
|
1065
|
+
description: "Most background Bash tasks (run_in_background) that may run at once in one conversation's sandbox, sub-agents included; a launch beyond it is refused",
|
|
1066
|
+
})),
|
|
1067
|
+
maxSeconds: z
|
|
1068
|
+
.number()
|
|
1069
|
+
.int()
|
|
1070
|
+
.positive()
|
|
1071
|
+
.default(7200)
|
|
1072
|
+
.meta(meta({
|
|
1073
|
+
description: "Longest a background Bash task may run, in seconds; the task is killed at its deadline and ends as timed_out. Clamped to sandbox.limits.maxCommandSeconds; not limited by runtime.maxRunSeconds",
|
|
1074
|
+
})),
|
|
1075
|
+
pollSeconds: z
|
|
1076
|
+
.number()
|
|
1077
|
+
.int()
|
|
1078
|
+
.min(1)
|
|
1079
|
+
.default(10)
|
|
1080
|
+
.meta(meta({
|
|
1081
|
+
description: "How often the worker checks the running background Bash tasks of every sandbox for a finish, in seconds; read when the worker starts",
|
|
1082
|
+
})),
|
|
1083
|
+
})
|
|
1084
|
+
.prefault({}),
|
|
983
1085
|
limits: z
|
|
984
1086
|
.object({
|
|
985
1087
|
cpu: z
|
|
@@ -27,6 +27,7 @@ export const parentReachable = (viewerAccountId) => (eb) => eb.or([
|
|
|
27
27
|
.whereRef("p.org_id", "=", "conversations.org_id")
|
|
28
28
|
.where("p.account_id", "=", viewerAccountId)
|
|
29
29
|
.where("p.kind", "=", "chat")
|
|
30
|
+
.where("p.deleted_at", "is", null)
|
|
30
31
|
.where("agents.deleted_at", "is", null)
|
|
31
32
|
.where(visibleTo(viewerAccountId))),
|
|
32
33
|
]);
|
|
@@ -53,6 +54,7 @@ let ConversationAccess = class ConversationAccess {
|
|
|
53
54
|
.where("conversations.id", "=", conversationId)
|
|
54
55
|
.where("conversations.org_id", "=", orgId)
|
|
55
56
|
.where("conversations.account_id", "=", viewerAccountId)
|
|
57
|
+
.where("conversations.deleted_at", "is", null)
|
|
56
58
|
.where("conversations.kind", "in", ["chat", "subagent"])
|
|
57
59
|
.where(parentReachable(viewerAccountId))
|
|
58
60
|
.where((eb) => eb.and([
|
|
@@ -20,7 +20,7 @@ export interface ArtifactPreview {
|
|
|
20
20
|
truncated: boolean;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* 产物(M5 T8 / T11):agent 经 `
|
|
23
|
+
* 产物(M5 T8 / T11):agent 经 `Deliver` 交付的文件。先按会话流的规则判定会话可见
|
|
24
24
|
* (不可见 → `conversation.not_found`),再只在这个会话的日志里找 `artifact_created`
|
|
25
25
|
* (没有 → `conversation.artifact_not_found`)。
|
|
26
26
|
*
|
|
@@ -62,7 +62,7 @@ async function readPrefix(body, max) {
|
|
|
62
62
|
return out.subarray(0, n);
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
-
* 产物(M5 T8 / T11):agent 经 `
|
|
65
|
+
* 产物(M5 T8 / T11):agent 经 `Deliver` 交付的文件。先按会话流的规则判定会话可见
|
|
66
66
|
* (不可见 → `conversation.not_found`),再只在这个会话的日志里找 `artifact_created`
|
|
67
67
|
* (没有 → `conversation.artifact_not_found`)。
|
|
68
68
|
*
|
|
@@ -28,6 +28,16 @@ export declare const MAX_PENDING_SKILL_PACKAGES = 5;
|
|
|
28
28
|
* `POST /skills` 开始处理时再顺延这么久,处理期间不会被清理。
|
|
29
29
|
*/
|
|
30
30
|
export declare const SKILL_PACKAGE_TTL_HOURS = 1;
|
|
31
|
+
/** The image types an agent avatar upload may have (cropped square in the browser). */
|
|
32
|
+
export declare const AGENT_AVATAR_CONTENT_TYPES: readonly ["image/png", "image/jpeg", "image/webp"];
|
|
33
|
+
/** The size limit of an agent avatar upload (bytes). */
|
|
34
|
+
export declare const AGENT_AVATAR_MAX_BYTES: number;
|
|
35
|
+
/** Unfinished avatar uploads one account may have in an org (counted apart from other uploads). */
|
|
36
|
+
export declare const MAX_PENDING_AGENT_AVATARS = 10;
|
|
37
|
+
/** An avatar upload not saved into a profile expires (and is cleaned up) after this many hours. */
|
|
38
|
+
export declare const AGENT_AVATAR_TTL_HOURS = 24;
|
|
39
|
+
/** Download redirect lifetime of an avatar (seconds); also its `Cache-Control` max-age. */
|
|
40
|
+
export declare const AGENT_AVATAR_DOWNLOAD_TTL_SECONDS = 300;
|
|
31
41
|
/**
|
|
32
42
|
* 技能包解出的文件在 `kernel/<orgId>/` 下的前缀:按上传 id,同一上传重试写到同一批键(幂等),
|
|
33
43
|
* 并发处理同一上传也不会互相覆盖出不同内容。版本行记下这个前缀(`skill_versions.object_prefix`)。
|
|
@@ -169,6 +179,26 @@ export declare class AttachmentsService {
|
|
|
169
179
|
* 不是该账号的 ready 技能包(如已被并发的请求用掉)→ `attachment.not_found`。
|
|
170
180
|
*/
|
|
171
181
|
consumeSkillPackage(orgId: string, accountId: string, id: string): Promise<void>;
|
|
182
|
+
/**
|
|
183
|
+
* Makes an agent avatar upload ready to be saved into a profile (outside any transaction: it may
|
|
184
|
+
* read the object store): only the uploader, only the `agent-avatar` purpose, an image type, not
|
|
185
|
+
* expired and not yet used by another agent, else `attachment.not_found`. An upload still
|
|
186
|
+
* `pending` is finalized first (size, type and the image signature are checked). The expiry is
|
|
187
|
+
* extended so the cleanup job cannot delete it before {@link consumeAgentAvatar} runs.
|
|
188
|
+
*/
|
|
189
|
+
prepareAgentAvatar(orgId: string, accountId: string, id: string, agentId: string): Promise<void>;
|
|
190
|
+
/**
|
|
191
|
+
* In the caller's transaction, binds a ready avatar upload to `agentId` (row lock; the expiry is
|
|
192
|
+
* cleared, so the cleanup job keeps it while the profile uses it). An upload another agent
|
|
193
|
+
* already uses, or one that is not the account's ready avatar → `attachment.not_found`; saving
|
|
194
|
+
* the same upload to the same agent again is fine.
|
|
195
|
+
*/
|
|
196
|
+
consumeAgentAvatar(orgId: string, accountId: string, id: string, agentId: string): Promise<void>;
|
|
197
|
+
/**
|
|
198
|
+
* A short-lived presigned GET (inline, with the checked image type) of the avatar upload bound
|
|
199
|
+
* to `agentId`; `null` when there is none or its object is gone or no longer the finalized one.
|
|
200
|
+
*/
|
|
201
|
+
agentAvatarUrl(orgId: string, agentId: string, id: string): Promise<string | null>;
|
|
172
202
|
/**
|
|
173
203
|
* 删除过期(`expires_at < now()`)且从未绑定到会话的附件:先把行认领为 `deleting`(`FOR UPDATE SKIP LOCKED`,
|
|
174
204
|
* 多副本并发时互不重复),再删对象、删行。删对象失败的行保持 `deleting`,下次运行重试。
|
|
@@ -40,6 +40,16 @@ export const MAX_PENDING_SKILL_PACKAGES = 5;
|
|
|
40
40
|
* `POST /skills` 开始处理时再顺延这么久,处理期间不会被清理。
|
|
41
41
|
*/
|
|
42
42
|
export const SKILL_PACKAGE_TTL_HOURS = 1;
|
|
43
|
+
/** The image types an agent avatar upload may have (cropped square in the browser). */
|
|
44
|
+
export const AGENT_AVATAR_CONTENT_TYPES = ["image/png", "image/jpeg", "image/webp"];
|
|
45
|
+
/** The size limit of an agent avatar upload (bytes). */
|
|
46
|
+
export const AGENT_AVATAR_MAX_BYTES = 2 * 1024 * 1024;
|
|
47
|
+
/** Unfinished avatar uploads one account may have in an org (counted apart from other uploads). */
|
|
48
|
+
export const MAX_PENDING_AGENT_AVATARS = 10;
|
|
49
|
+
/** An avatar upload not saved into a profile expires (and is cleaned up) after this many hours. */
|
|
50
|
+
export const AGENT_AVATAR_TTL_HOURS = 24;
|
|
51
|
+
/** Download redirect lifetime of an avatar (seconds); also its `Cache-Control` max-age. */
|
|
52
|
+
export const AGENT_AVATAR_DOWNLOAD_TTL_SECONDS = 300;
|
|
43
53
|
/**
|
|
44
54
|
* 技能包解出的文件在 `kernel/<orgId>/` 下的前缀:按上传 id,同一上传重试写到同一批键(幂等),
|
|
45
55
|
* 并发处理同一上传也不会互相覆盖出不同内容。版本行记下这个前缀(`skill_versions.object_prefix`)。
|
|
@@ -56,7 +66,11 @@ const notFound = () => new ApiError("attachment.not_found", "Attachment not foun
|
|
|
56
66
|
export const normalizeContentType = (ct) => (ct.split(";")[0] ?? "").trim().toLowerCase();
|
|
57
67
|
const isImage = (ct) => IMAGE_MEDIA_TYPES.includes(ct);
|
|
58
68
|
/** 对象键:只用附件 id,用户的文件名不进键。技能包另放 `skill-packages/<id>`。 */
|
|
59
|
-
const objectKey = (id, purpose = "chat") => purpose === "chat"
|
|
69
|
+
const objectKey = (id, purpose = "chat") => purpose === "chat"
|
|
70
|
+
? `attachments/${id}`
|
|
71
|
+
: purpose === "agent-avatar"
|
|
72
|
+
? `agent-avatars/${id}`
|
|
73
|
+
: `skill-packages/${id}`;
|
|
60
74
|
const startsWith = (b, sig, at = 0) => sig.every((x, i) => b[at + i] === x);
|
|
61
75
|
const ascii = (s) => [...s].map((c) => c.charCodeAt(0));
|
|
62
76
|
/** 文件开头是否与声明的类型相符(图片与 PDF 看签名,文本不能含 NUL)。 */
|
|
@@ -139,12 +153,19 @@ let AttachmentsService = class AttachmentsService {
|
|
|
139
153
|
const cfg = this.config.get().attachments;
|
|
140
154
|
const contentType = normalizeContentType(input.contentType);
|
|
141
155
|
const skill = purpose === "skill-package";
|
|
156
|
+
const avatar = purpose === "agent-avatar";
|
|
142
157
|
if (skill
|
|
143
158
|
? contentType !== SKILL_PACKAGE_CONTENT_TYPE
|
|
144
|
-
:
|
|
159
|
+
: avatar
|
|
160
|
+
? !AGENT_AVATAR_CONTENT_TYPES.includes(contentType)
|
|
161
|
+
: !cfg.allowedTypes.includes(contentType)) {
|
|
145
162
|
throw new ApiError("attachment.type_not_allowed", `Attachment type ${JSON.stringify(contentType)} is not allowed`);
|
|
146
163
|
}
|
|
147
|
-
const limit = skill
|
|
164
|
+
const limit = skill
|
|
165
|
+
? SKILL_PACKAGE_UPLOAD_MAX_BYTES
|
|
166
|
+
: avatar
|
|
167
|
+
? AGENT_AVATAR_MAX_BYTES
|
|
168
|
+
: this.limitFor(contentType);
|
|
148
169
|
if (input.size > limit) {
|
|
149
170
|
throw new ApiError("attachment.too_large", `Attachment is ${input.size} bytes, over the limit of ${limit} bytes`);
|
|
150
171
|
}
|
|
@@ -156,13 +177,21 @@ let AttachmentsService = class AttachmentsService {
|
|
|
156
177
|
.where("status", "=", "pending")
|
|
157
178
|
.where("purpose", "=", purpose)
|
|
158
179
|
.executeTakeFirst();
|
|
159
|
-
const maxPending = skill
|
|
180
|
+
const maxPending = skill
|
|
181
|
+
? MAX_PENDING_SKILL_PACKAGES
|
|
182
|
+
: avatar
|
|
183
|
+
? MAX_PENDING_AGENT_AVATARS
|
|
184
|
+
: MAX_PENDING_ATTACHMENTS;
|
|
160
185
|
if (Number(pending?.n ?? 0) >= maxPending) {
|
|
161
186
|
throw new ApiError("attachment.too_many_pending", `Too many unfinished uploads (at most ${maxPending}); finish or wait for them first`);
|
|
162
187
|
}
|
|
163
188
|
const id = randomUUID();
|
|
164
189
|
const key = objectKey(id, purpose);
|
|
165
|
-
const ttlHours = skill
|
|
190
|
+
const ttlHours = skill
|
|
191
|
+
? SKILL_PACKAGE_TTL_HOURS
|
|
192
|
+
: avatar
|
|
193
|
+
? AGENT_AVATAR_TTL_HOURS
|
|
194
|
+
: cfg.unboundTtlHours;
|
|
166
195
|
const upload = await this.storage.kernel(orgId).presignPut(key, {
|
|
167
196
|
contentType,
|
|
168
197
|
maxSize: input.size,
|
|
@@ -541,6 +570,99 @@ let AttachmentsService = class AttachmentsService {
|
|
|
541
570
|
.where("id", "=", id)
|
|
542
571
|
.execute();
|
|
543
572
|
}
|
|
573
|
+
/**
|
|
574
|
+
* Makes an agent avatar upload ready to be saved into a profile (outside any transaction: it may
|
|
575
|
+
* read the object store): only the uploader, only the `agent-avatar` purpose, an image type, not
|
|
576
|
+
* expired and not yet used by another agent, else `attachment.not_found`. An upload still
|
|
577
|
+
* `pending` is finalized first (size, type and the image signature are checked). The expiry is
|
|
578
|
+
* extended so the cleanup job cannot delete it before {@link consumeAgentAvatar} runs.
|
|
579
|
+
*/
|
|
580
|
+
async prepareAgentAvatar(orgId, accountId, id, agentId) {
|
|
581
|
+
this.storage.assertAvailable();
|
|
582
|
+
const row = await this.db
|
|
583
|
+
.selectFrom("attachments")
|
|
584
|
+
.select([
|
|
585
|
+
"status",
|
|
586
|
+
"purpose",
|
|
587
|
+
"content_type",
|
|
588
|
+
"agent_id",
|
|
589
|
+
sql `expires_at is not null and expires_at <= now()`.as("expired"),
|
|
590
|
+
])
|
|
591
|
+
.where("id", "=", id)
|
|
592
|
+
.where("org_id", "=", orgId)
|
|
593
|
+
.where("account_id", "=", accountId)
|
|
594
|
+
.executeTakeFirst();
|
|
595
|
+
if (row?.purpose !== "agent-avatar" ||
|
|
596
|
+
row.status === "deleting" ||
|
|
597
|
+
row.expired ||
|
|
598
|
+
(row.agent_id !== null && row.agent_id !== agentId) ||
|
|
599
|
+
!AGENT_AVATAR_CONTENT_TYPES.includes(row.content_type)) {
|
|
600
|
+
throw notFound();
|
|
601
|
+
}
|
|
602
|
+
if (row.status === "pending")
|
|
603
|
+
await this.finalize(orgId, accountId, id);
|
|
604
|
+
await this.db
|
|
605
|
+
.updateTable("attachments")
|
|
606
|
+
.set({ expires_at: sql `now() + make_interval(hours => ${AGENT_AVATAR_TTL_HOURS})` })
|
|
607
|
+
.where("id", "=", id)
|
|
608
|
+
.where("status", "=", "ready")
|
|
609
|
+
.where("agent_id", "is", null)
|
|
610
|
+
.where("expires_at", "is not", null)
|
|
611
|
+
.execute();
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* In the caller's transaction, binds a ready avatar upload to `agentId` (row lock; the expiry is
|
|
615
|
+
* cleared, so the cleanup job keeps it while the profile uses it). An upload another agent
|
|
616
|
+
* already uses, or one that is not the account's ready avatar → `attachment.not_found`; saving
|
|
617
|
+
* the same upload to the same agent again is fine.
|
|
618
|
+
*/
|
|
619
|
+
async consumeAgentAvatar(orgId, accountId, id, agentId) {
|
|
620
|
+
const trx = this.db.db;
|
|
621
|
+
const row = await trx
|
|
622
|
+
.selectFrom("attachments")
|
|
623
|
+
.select(["status", "agent_id"])
|
|
624
|
+
.where("id", "=", id)
|
|
625
|
+
.where("org_id", "=", orgId)
|
|
626
|
+
.where("account_id", "=", accountId)
|
|
627
|
+
.where("purpose", "=", "agent-avatar")
|
|
628
|
+
.forUpdate()
|
|
629
|
+
.executeTakeFirst();
|
|
630
|
+
if (row?.status !== "ready" || (row.agent_id !== null && row.agent_id !== agentId)) {
|
|
631
|
+
throw notFound();
|
|
632
|
+
}
|
|
633
|
+
await trx
|
|
634
|
+
.updateTable("attachments")
|
|
635
|
+
.set({ agent_id: agentId, expires_at: null })
|
|
636
|
+
.where("id", "=", id)
|
|
637
|
+
.execute();
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* A short-lived presigned GET (inline, with the checked image type) of the avatar upload bound
|
|
641
|
+
* to `agentId`; `null` when there is none or its object is gone or no longer the finalized one.
|
|
642
|
+
*/
|
|
643
|
+
async agentAvatarUrl(orgId, agentId, id) {
|
|
644
|
+
this.storage.assertAvailable();
|
|
645
|
+
const row = await this.db
|
|
646
|
+
.selectFrom("attachments")
|
|
647
|
+
.select(["content_type", "object_key", "etag"])
|
|
648
|
+
.where("id", "=", id)
|
|
649
|
+
.where("org_id", "=", orgId)
|
|
650
|
+
.where("agent_id", "=", agentId)
|
|
651
|
+
.where("purpose", "=", "agent-avatar")
|
|
652
|
+
.where("status", "=", "ready")
|
|
653
|
+
.executeTakeFirst();
|
|
654
|
+
if (!row)
|
|
655
|
+
return null;
|
|
656
|
+
const store = this.storage.kernel(orgId);
|
|
657
|
+
const head = await store.head(row.object_key);
|
|
658
|
+
if (!head || !this.sameContent(row.etag, head.etag, { orgId, attachmentId: id }))
|
|
659
|
+
return null;
|
|
660
|
+
return store.presignGet(row.object_key, {
|
|
661
|
+
ttlSeconds: AGENT_AVATAR_DOWNLOAD_TTL_SECONDS,
|
|
662
|
+
disposition: "inline",
|
|
663
|
+
responseContentType: row.content_type,
|
|
664
|
+
});
|
|
665
|
+
}
|
|
544
666
|
/**
|
|
545
667
|
* 删除过期(`expires_at < now()`)且从未绑定到会话的附件:先把行认领为 `deleting`(`FOR UPDATE SKIP LOCKED`,
|
|
546
668
|
* 多副本并发时互不重复),再删对象、删行。删对象失败的行保持 `deleting`,下次运行重试。
|
|
@@ -613,6 +735,9 @@ __decorate([
|
|
|
613
735
|
__decorate([
|
|
614
736
|
Transactional({ propagation: "mandatory" })
|
|
615
737
|
], AttachmentsService.prototype, "consumeSkillPackage", null);
|
|
738
|
+
__decorate([
|
|
739
|
+
Transactional({ propagation: "mandatory" })
|
|
740
|
+
], AttachmentsService.prototype, "consumeAgentAvatar", null);
|
|
616
741
|
AttachmentsService = __decorate([
|
|
617
742
|
Injectable(),
|
|
618
743
|
__param(0, Inject(KernelDb)),
|
|
@@ -12,11 +12,27 @@ import type { QueueItem, QueuePauseReason } from "./queue.js";
|
|
|
12
12
|
import { ConversationQueue } from "./queue.service.js";
|
|
13
13
|
import { ConversationSandboxStatus, type SandboxStatusView } from "./sandbox-status.js";
|
|
14
14
|
declare const ListQuery: z.ZodObject<{
|
|
15
|
+
q: z.ZodOptional<z.ZodString>;
|
|
16
|
+
state: z.ZodOptional<z.ZodEnum<{
|
|
17
|
+
running: "running";
|
|
18
|
+
waiting: "waiting";
|
|
19
|
+
}>>;
|
|
20
|
+
archived: z.ZodOptional<z.ZodEnum<{
|
|
21
|
+
1: "1";
|
|
22
|
+
}>>;
|
|
15
23
|
after: z.ZodOptional<z.ZodString>;
|
|
16
24
|
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
17
25
|
agentId: z.ZodOptional<z.ZodString>;
|
|
18
26
|
}, z.core.$strip>;
|
|
19
27
|
declare const GroupsQuery: z.ZodObject<{
|
|
28
|
+
q: z.ZodOptional<z.ZodString>;
|
|
29
|
+
state: z.ZodOptional<z.ZodEnum<{
|
|
30
|
+
running: "running";
|
|
31
|
+
waiting: "waiting";
|
|
32
|
+
}>>;
|
|
33
|
+
archived: z.ZodOptional<z.ZodEnum<{
|
|
34
|
+
1: "1";
|
|
35
|
+
}>>;
|
|
20
36
|
perGroup: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
21
37
|
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
22
38
|
after: z.ZodOptional<z.ZodString>;
|
|
@@ -142,9 +158,13 @@ declare const QueueEditBody: z.ZodObject<{
|
|
|
142
158
|
* A rename: 1–120 characters counted in code points after trimming, with no control or format
|
|
143
159
|
* (bidi, zero-width) characters, the same rule generated and tool titles follow.
|
|
144
160
|
*/
|
|
145
|
-
declare const
|
|
146
|
-
title: z.ZodString
|
|
161
|
+
declare const PatchBody: z.ZodObject<{
|
|
162
|
+
title: z.ZodOptional<z.ZodString>;
|
|
163
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
147
164
|
}, z.core.$strict>;
|
|
165
|
+
declare const IdParams: z.ZodObject<{
|
|
166
|
+
id: z.ZodString;
|
|
167
|
+
}, z.core.$strip>;
|
|
148
168
|
/**
|
|
149
169
|
* 会话(`/api/v1/orgs/:orgId/conversations`):`agents.use`(访客以上),只接受人类用户;
|
|
150
170
|
* 服务令牌 → 403 `forbidden`。只有会话所有者可见,其他人一律 `conversation.not_found`。
|
|
@@ -158,15 +178,25 @@ export declare class ConversationsController {
|
|
|
158
178
|
private readonly queue;
|
|
159
179
|
private readonly files;
|
|
160
180
|
constructor(conversations: ConversationsService, outputs: ConversationOutputs, artifacts: ConversationArtifacts, sandboxStatus: ConversationSandboxStatus, toolInfo: ConversationToolInfo, queue: ConversationQueue, files: ConversationFiles);
|
|
161
|
-
/**
|
|
181
|
+
/**
|
|
182
|
+
* 201 when created; 200 when `message.clientMessageId` repeats an earlier first send. With a
|
|
183
|
+
* message the answer has `event` (the `user_message`) and `events`: every event the first send
|
|
184
|
+
* wrote, in seq order from seq 1 (a `model_switched` first when it switched).
|
|
185
|
+
*/
|
|
162
186
|
create(principal: Principal, org: OrgContext, body: z.infer<typeof CreateBody>, reply: FastifyReply): Promise<{
|
|
163
187
|
conversation: ConversationView;
|
|
164
188
|
event?: ConversationEvent;
|
|
189
|
+
events?: ConversationEvent[];
|
|
165
190
|
}>;
|
|
166
|
-
/**
|
|
167
|
-
|
|
191
|
+
/**
|
|
192
|
+
* Rename and / or archive (owner only). A rename makes `titleSource` `manual`, so the title is
|
|
193
|
+
* never regenerated; `archived` archives or unarchives. Returns the final view.
|
|
194
|
+
*/
|
|
195
|
+
patch(principal: Principal, org: OrgContext, id: string, body: z.infer<typeof PatchBody>): Promise<{
|
|
168
196
|
conversation: ConversationView;
|
|
169
197
|
}>;
|
|
198
|
+
/** Soft delete (owner only): stops an active run and hides the conversation everywhere. */
|
|
199
|
+
remove(principal: Principal, org: OrgContext, { id }: z.infer<typeof IdParams>): Promise<void>;
|
|
170
200
|
/** 我的会话,最近更新的在前:`next` 为下一页游标(作为 `after` 传回),没有更多时为 null。 */
|
|
171
201
|
list(principal: Principal, org: OrgContext, q: z.infer<typeof ListQuery>): Promise<{
|
|
172
202
|
conversations: ConversationView[];
|
|
@@ -180,6 +210,7 @@ export declare class ConversationsController {
|
|
|
180
210
|
groups(principal: Principal, org: OrgContext, q: z.infer<typeof GroupsQuery>): Promise<{
|
|
181
211
|
groups: ConversationGroup[];
|
|
182
212
|
next: string | null;
|
|
213
|
+
archivedCount: number;
|
|
183
214
|
}>;
|
|
184
215
|
get(principal: Principal, org: OrgContext, id: string): Promise<{
|
|
185
216
|
conversation: ConversationView;
|
|
@@ -12,7 +12,7 @@ import { z } from "zod";
|
|
|
12
12
|
import { ModelRef } from "../agents/definition.js";
|
|
13
13
|
import { CurrentPrincipal, requireUser } from "../identity/principal.js";
|
|
14
14
|
import { createZodDto } from "../infra/validation/create-zod-dto.js";
|
|
15
|
-
import { ZBody, ZQuery } from "../infra/validation/zod-params.js";
|
|
15
|
+
import { ZBody, ZParam, ZQuery } from "../infra/validation/zod-params.js";
|
|
16
16
|
import { CurrentOrg, OrgAction } from "../orgs/org.guard.js";
|
|
17
17
|
import { CONTROL_OR_HIDDEN_RE } from "../text.js";
|
|
18
18
|
import { MAX_ATTACHMENTS } from "../tools/connector-content.js";
|
|
@@ -23,17 +23,25 @@ import { ConversationFiles, FILE_CONTENT_MAX_BYTES, FILES_PAGE_MAX, } from "./fi
|
|
|
23
23
|
import { ConversationOutputs, OUTPUT_PAGE_MAX_CHARS } from "./outputs-read.js";
|
|
24
24
|
import { ConversationQueue } from "./queue.service.js";
|
|
25
25
|
import { ConversationSandboxStatus } from "./sandbox-status.js";
|
|
26
|
+
/** Shared by the list and groups queries: title search, run activity and the archived list. */
|
|
27
|
+
const searchFields = {
|
|
28
|
+
q: z.string().min(1).max(100).optional(),
|
|
29
|
+
state: z.enum(["running", "waiting"]).optional(),
|
|
30
|
+
archived: z.enum(["1"]).optional(),
|
|
31
|
+
};
|
|
26
32
|
const ListQuery = z.object({
|
|
27
33
|
after: z.string().min(1).max(100).optional(),
|
|
28
34
|
limit: z.coerce.number().int().min(1).max(200).default(50),
|
|
29
35
|
/** Only this agent's conversations (the sidebar's per-group "More"). */
|
|
30
36
|
agentId: z.string().min(1).max(100).optional(),
|
|
37
|
+
...searchFields,
|
|
31
38
|
});
|
|
32
39
|
const GroupsQuery = z.object({
|
|
33
40
|
perGroup: z.coerce.number().int().min(1).max(20).default(5),
|
|
34
41
|
limit: z.coerce.number().int().min(1).max(50).default(20),
|
|
35
42
|
/** The last group's agent id from the previous page (`next`). */
|
|
36
43
|
after: z.string().min(1).max(100).optional(),
|
|
44
|
+
...searchFields,
|
|
37
45
|
});
|
|
38
46
|
const SubagentsQuery = z.object({
|
|
39
47
|
/** The previous page's last sub-agent id (`next`). */
|
|
@@ -143,7 +151,7 @@ const QueueEditBody = z.object({ text: z.string().max(100_000) }).strict();
|
|
|
143
151
|
* A rename: 1–120 characters counted in code points after trimming, with no control or format
|
|
144
152
|
* (bidi, zero-width) characters, the same rule generated and tool titles follow.
|
|
145
153
|
*/
|
|
146
|
-
const
|
|
154
|
+
const PatchBody = z
|
|
147
155
|
.object({
|
|
148
156
|
title: z
|
|
149
157
|
.string()
|
|
@@ -151,12 +159,19 @@ const RenameBody = z
|
|
|
151
159
|
.trim()
|
|
152
160
|
.refine((t) => t.length > 0, "title must not be empty")
|
|
153
161
|
.refine((t) => Array.from(t).length <= CONVERSATION_TITLE_MAX_CHARS, `title must be at most ${CONVERSATION_TITLE_MAX_CHARS} characters`)
|
|
154
|
-
.refine((t) => !CONTROL_OR_HIDDEN_RE.test(t), "title must not contain control or format characters")
|
|
162
|
+
.refine((t) => !CONTROL_OR_HIDDEN_RE.test(t), "title must not contain control or format characters")
|
|
163
|
+
.optional(),
|
|
164
|
+
/** true archives (hidden from the default lists), false unarchives. */
|
|
165
|
+
archived: z.boolean().optional(),
|
|
155
166
|
})
|
|
156
|
-
.strict()
|
|
167
|
+
.strict()
|
|
168
|
+
.refine((b) => b.title !== undefined || b.archived !== undefined, "title or archived is required");
|
|
169
|
+
const IdParams = z.object({ id: z.string().min(1).max(100) });
|
|
157
170
|
class ConversationCreateBodyDto extends createZodDto(CreateBody, "ConversationCreateBody") {
|
|
158
171
|
}
|
|
159
|
-
class
|
|
172
|
+
class ConversationPatchBodyDto extends createZodDto(PatchBody, "ConversationPatchBody") {
|
|
173
|
+
}
|
|
174
|
+
class ConversationIdParamsDto extends createZodDto(IdParams, "ConversationIdParams") {
|
|
160
175
|
}
|
|
161
176
|
class ConversationListQueryDto extends createZodDto(ListQuery, "ConversationListQuery") {
|
|
162
177
|
}
|
|
@@ -203,7 +218,11 @@ let ConversationsController = class ConversationsController {
|
|
|
203
218
|
this.queue = queue;
|
|
204
219
|
this.files = files;
|
|
205
220
|
}
|
|
206
|
-
/**
|
|
221
|
+
/**
|
|
222
|
+
* 201 when created; 200 when `message.clientMessageId` repeats an earlier first send. With a
|
|
223
|
+
* message the answer has `event` (the `user_message`) and `events`: every event the first send
|
|
224
|
+
* wrote, in seq order from seq 1 (a `model_switched` first when it switched).
|
|
225
|
+
*/
|
|
207
226
|
async create(principal, org, body, reply) {
|
|
208
227
|
const p = requireUser(principal);
|
|
209
228
|
if (body.message === undefined) {
|
|
@@ -222,15 +241,32 @@ let ConversationsController = class ConversationsController {
|
|
|
222
241
|
...(m.skill !== undefined && { skill: m.skill }),
|
|
223
242
|
});
|
|
224
243
|
reply.status(out.created ? 201 : 200);
|
|
225
|
-
return { conversation: out.conversation, event: out.event };
|
|
244
|
+
return { conversation: out.conversation, event: out.event, events: out.events };
|
|
226
245
|
}
|
|
227
|
-
/**
|
|
228
|
-
|
|
246
|
+
/**
|
|
247
|
+
* Rename and / or archive (owner only). A rename makes `titleSource` `manual`, so the title is
|
|
248
|
+
* never regenerated; `archived` archives or unarchives. Returns the final view.
|
|
249
|
+
*/
|
|
250
|
+
async patch(principal, org, id, body) {
|
|
229
251
|
const p = requireUser(principal);
|
|
252
|
+
const renamed = body.title === undefined
|
|
253
|
+
? undefined
|
|
254
|
+
: await this.conversations.rename(org.orgId, id, p.account.id, body.title);
|
|
255
|
+
if (body.archived === undefined) {
|
|
256
|
+
// The refine guarantees a title when there is no `archived`
|
|
257
|
+
return {
|
|
258
|
+
conversation: renamed ?? (await this.conversations.get(org.orgId, id, p.account.id)),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
230
261
|
return {
|
|
231
|
-
conversation: await this.conversations.
|
|
262
|
+
conversation: await this.conversations.setArchived(org.orgId, id, p.account.id, body.archived),
|
|
232
263
|
};
|
|
233
264
|
}
|
|
265
|
+
/** Soft delete (owner only): stops an active run and hides the conversation everywhere. */
|
|
266
|
+
async remove(principal, org, { id }) {
|
|
267
|
+
const p = requireUser(principal);
|
|
268
|
+
await this.conversations.remove(org.orgId, id, p.account.id);
|
|
269
|
+
}
|
|
234
270
|
/** 我的会话,最近更新的在前:`next` 为下一页游标(作为 `after` 传回),没有更多时为 null。 */
|
|
235
271
|
async list(principal, org, q) {
|
|
236
272
|
const p = requireUser(principal);
|
|
@@ -238,6 +274,9 @@ let ConversationsController = class ConversationsController {
|
|
|
238
274
|
limit: q.limit + 1,
|
|
239
275
|
...(q.after !== undefined && { after: q.after }),
|
|
240
276
|
...(q.agentId !== undefined && { agentId: q.agentId }),
|
|
277
|
+
...(q.q !== undefined && { q: q.q }),
|
|
278
|
+
...(q.state !== undefined && { state: q.state }),
|
|
279
|
+
...(q.archived !== undefined && { archived: true }),
|
|
241
280
|
});
|
|
242
281
|
const conversations = rows.slice(0, q.limit);
|
|
243
282
|
const next = rows.length > q.limit ? (conversations.at(-1)?.id ?? null) : null;
|
|
@@ -254,6 +293,9 @@ let ConversationsController = class ConversationsController {
|
|
|
254
293
|
perGroup: q.perGroup,
|
|
255
294
|
limit: q.limit,
|
|
256
295
|
...(q.after !== undefined && { after: q.after }),
|
|
296
|
+
...(q.q !== undefined && { q: q.q }),
|
|
297
|
+
...(q.state !== undefined && { state: q.state }),
|
|
298
|
+
...(q.archived !== undefined && { archived: true }),
|
|
257
299
|
});
|
|
258
300
|
}
|
|
259
301
|
async get(principal, org, id) {
|
|
@@ -443,8 +485,16 @@ __decorate([
|
|
|
443
485
|
__param(0, CurrentPrincipal()),
|
|
444
486
|
__param(1, CurrentOrg()),
|
|
445
487
|
__param(2, Param("id")),
|
|
446
|
-
__param(3, ZBody(
|
|
447
|
-
], ConversationsController.prototype, "
|
|
488
|
+
__param(3, ZBody(ConversationPatchBodyDto))
|
|
489
|
+
], ConversationsController.prototype, "patch", null);
|
|
490
|
+
__decorate([
|
|
491
|
+
Delete(":id"),
|
|
492
|
+
HttpCode(204),
|
|
493
|
+
OrgAction("agents.use"),
|
|
494
|
+
__param(0, CurrentPrincipal()),
|
|
495
|
+
__param(1, CurrentOrg()),
|
|
496
|
+
__param(2, ZParam(ConversationIdParamsDto))
|
|
497
|
+
], ConversationsController.prototype, "remove", null);
|
|
448
498
|
__decorate([
|
|
449
499
|
Get(),
|
|
450
500
|
OrgAction("agents.use"),
|
|
@@ -6,6 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { Module } from "@nestjs/common";
|
|
8
8
|
import { AgentLookupModule } from "../agents/agent-lookup.js";
|
|
9
|
+
import { BackgroundModule } from "../background/background.module.js";
|
|
9
10
|
import { ProvidersModule } from "../runtime/providers.js";
|
|
10
11
|
import { RuntimeModule } from "../runtime/runtime.module.js";
|
|
11
12
|
import { SandboxModule } from "../sandbox/sandbox.module.js";
|
|
@@ -44,6 +45,8 @@ ConversationsModule = __decorate([
|
|
|
44
45
|
ProvidersModule,
|
|
45
46
|
// the sandbox status
|
|
46
47
|
SandboxModule,
|
|
48
|
+
// the stop of a deleted conversation's background tasks
|
|
49
|
+
BackgroundModule,
|
|
47
50
|
],
|
|
48
51
|
providers: [
|
|
49
52
|
ConversationsService,
|