@capybara-hq/kernel 0.1.0-rc.6 → 0.1.0-rc.7
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/bootstrap.json +27 -3
- package/dist/admin/admin.controller.d.ts +8 -72
- package/dist/admin/admin.controller.js +21 -46
- package/dist/admin/admin.schemas.d.ts +57 -0
- package/dist/admin/admin.schemas.js +50 -0
- package/dist/admin/extensions.controller.d.ts +10 -0
- package/dist/admin/extensions.controller.js +18 -0
- package/dist/admin/extensions.schemas.d.ts +7 -0
- package/dist/admin/extensions.schemas.js +10 -0
- package/dist/admin/limit-defaults.d.ts +20 -0
- package/dist/admin/limit-defaults.js +10 -0
- package/dist/agents/agent-profile.service.d.ts +7 -5
- package/dist/agents/agent-profile.service.js +14 -9
- package/dist/agents/agents.controller.d.ts +7 -287
- package/dist/agents/agents.controller.js +7 -67
- package/dist/agents/agents.schemas.d.ts +389 -0
- package/dist/agents/agents.schemas.js +126 -0
- package/dist/agents/agents.service.d.ts +13 -5
- package/dist/agents/agents.service.js +67 -13
- package/dist/agents/definition.d.ts +47 -19
- package/dist/agents/definition.js +119 -38
- package/dist/agents/from-template.d.ts +2 -2
- package/dist/agents/from-template.js +76 -45
- package/dist/agents/from-template.service.d.ts +12 -0
- package/dist/agents/from-template.service.js +20 -3
- package/dist/agents/models.controller.d.ts +1 -2
- package/dist/agents/models.controller.js +1 -1
- package/dist/agents/org-templates.d.ts +13 -3
- package/dist/agents/org-templates.js +69 -28
- package/dist/agents/pending-connector-requests.d.ts +2 -0
- package/dist/agents/pending-connector-requests.js +1 -1
- package/dist/agents/pending-connectors.controller.d.ts +1 -1
- package/dist/agents/pending-connectors.controller.js +2 -2
- package/dist/agents/pending-connectors.service.d.ts +2 -2
- package/dist/agents/pending-connectors.service.js +19 -19
- package/dist/agents/profile.d.ts +18 -0
- package/dist/agents/profile.js +5 -1
- package/dist/agents/templates.controller.d.ts +8 -17
- package/dist/agents/templates.controller.js +13 -31
- package/dist/agents/templates.schemas.d.ts +20 -0
- package/dist/agents/templates.schemas.js +45 -0
- package/dist/background/background.controller.js +3 -2
- package/dist/background/background.schemas.d.ts +10 -0
- package/dist/background/background.schemas.js +16 -0
- package/dist/background/tasks.service.d.ts +1 -1
- package/dist/background/tasks.service.js +7 -2
- package/dist/catalog/admin-catalog.controller.d.ts +4 -57
- package/dist/catalog/admin-catalog.controller.js +8 -45
- package/dist/catalog/admin-catalog.schemas.d.ts +72 -0
- package/dist/catalog/admin-catalog.schemas.js +92 -0
- package/dist/catalog/catalog-content.d.ts +12 -2
- package/dist/catalog/catalog-scope.service.js +8 -2
- package/dist/catalog/catalog.service.d.ts +2 -0
- package/dist/catalog/catalog.service.js +3 -0
- package/dist/catalog/component-scope.controller.d.ts +3 -65
- package/dist/catalog/component-scope.controller.js +3 -56
- package/dist/catalog/component-scope.schemas.d.ts +114 -0
- package/dist/catalog/component-scope.schemas.js +97 -0
- package/dist/catalog/component-scope.service.d.ts +28 -4
- package/dist/catalog/component-scope.service.js +55 -3
- package/dist/catalog/component-state.d.ts +9 -2
- package/dist/catalog/component-state.js +22 -13
- package/dist/catalog/marketplaces.controller.d.ts +5 -35
- package/dist/catalog/marketplaces.controller.js +6 -34
- package/dist/catalog/marketplaces.schemas.d.ts +48 -0
- package/dist/catalog/marketplaces.schemas.js +53 -0
- package/dist/catalog/marketplaces.service.d.ts +15 -1
- package/dist/catalog/marketplaces.service.js +22 -1
- package/dist/catalog/org-catalog.controller.d.ts +6 -62
- package/dist/catalog/org-catalog.controller.js +12 -66
- package/dist/catalog/org-catalog.schemas.d.ts +79 -0
- package/dist/catalog/org-catalog.schemas.js +82 -0
- package/dist/catalog/org-catalog.service.d.ts +9 -2
- package/dist/catalog/org-catalog.service.js +38 -5
- package/dist/catalog/org-extension.controller.d.ts +1 -12
- package/dist/catalog/org-extension.controller.js +1 -10
- package/dist/catalog/org-extension.schemas.d.ts +15 -0
- package/dist/catalog/org-extension.schemas.js +22 -0
- package/dist/catalog/org-plugin-uploads.controller.d.ts +2 -19
- package/dist/catalog/org-plugin-uploads.controller.js +15 -28
- package/dist/catalog/org-plugin-uploads.schemas.d.ts +20 -0
- package/dist/catalog/org-plugin-uploads.schemas.js +32 -0
- package/dist/catalog/owned-items.d.ts +6 -2
- package/dist/catalog/owned-items.js +16 -4
- package/dist/catalog/platform-components.d.ts +2 -0
- package/dist/catalog/platform-components.js +2 -0
- package/dist/catalog/plugin-import.js +1 -0
- package/dist/catalog/plugin-install.js +1 -1
- package/dist/catalog/requests.service.d.ts +2 -1
- package/dist/catalog/requests.service.js +6 -2
- package/dist/channels/channels.schemas.d.ts +33 -0
- package/dist/channels/channels.schemas.js +34 -0
- package/dist/channels/connections.controller.d.ts +2 -29
- package/dist/channels/connections.controller.js +1 -23
- package/dist/channels/connections.service.d.ts +8 -2
- package/dist/channels/connections.service.js +23 -5
- package/dist/channels/inbound.js +4 -0
- package/dist/conversations/conversations.controller.d.ts +16 -37
- package/dist/conversations/conversations.controller.js +16 -56
- package/dist/conversations/conversations.schemas.d.ts +52 -0
- package/dist/conversations/conversations.schemas.js +79 -0
- package/dist/conversations/conversations.service.d.ts +9 -1
- package/dist/conversations/conversations.service.js +23 -18
- package/dist/conversations/events.d.ts +80 -6
- package/dist/conversations/events.js +60 -5
- package/dist/conversations/message-context.d.ts +28 -0
- package/dist/conversations/message-context.js +56 -0
- package/dist/conversations/queue.d.ts +2 -1
- package/dist/conversations/queue.js +11 -2
- package/dist/db/kernel-schema.d.ts +20 -0
- package/dist/environments/environments.schemas.d.ts +3 -0
- package/dist/environments/environments.schemas.js +14 -0
- package/dist/environments/environments.service.d.ts +16 -4
- package/dist/environments/environments.service.js +58 -13
- package/dist/errors.d.ts +3 -0
- package/dist/errors.js +3 -0
- package/dist/evals/evals.schemas.d.ts +110 -0
- package/dist/evals/evals.schemas.js +107 -0
- package/dist/evals/reconstruct.js +18 -11
- package/dist/evals/recorded-tools.d.ts +2 -1
- package/dist/evals/recorded-tools.js +11 -3
- package/dist/evals/run-replay.d.ts +8 -1
- package/dist/evals/run-replay.js +13 -0
- package/dist/evals/runs.controller.d.ts +2 -57
- package/dist/evals/runs.controller.js +1 -42
- package/dist/evals/runs.service.d.ts +6 -6
- package/dist/evals/runs.service.js +32 -18
- package/dist/evals/sets.controller.d.ts +2 -28
- package/dist/evals/sets.controller.js +1 -31
- package/dist/evals/sets.service.d.ts +7 -7
- package/dist/evals/sets.service.js +23 -17
- package/dist/evals/snapshot.d.ts +3 -2
- package/dist/evals/snapshot.js +17 -4
- package/dist/extensions/admin-ops.d.ts +5 -3
- package/dist/extensions/admin-ops.js +17 -12
- package/dist/extensions/deployment-config.d.ts +16 -1
- package/dist/extensions/deployment-config.js +83 -0
- package/dist/extensions/extensions.module.js +3 -0
- package/dist/extensions/host.d.ts +33 -2
- package/dist/extensions/host.js +107 -1
- package/dist/extensions/installs.d.ts +5 -0
- package/dist/extensions/installs.js +12 -0
- package/dist/extensions/org-config.d.ts +17 -2
- package/dist/extensions/org-config.js +23 -4
- package/dist/extensions/point-defaults.controller.d.ts +2 -8
- package/dist/extensions/point-defaults.controller.js +1 -3
- package/dist/extensions/point-defaults.d.ts +3 -1
- package/dist/extensions/point-defaults.js +4 -2
- package/dist/extensions/point-defaults.schemas.d.ts +9 -0
- package/dist/extensions/point-defaults.schemas.js +14 -0
- package/dist/extensions/unavailable.d.ts +49 -0
- package/dist/extensions/unavailable.js +113 -0
- package/dist/files/previewers.controller.js +2 -3
- package/dist/files/previewers.d.ts +1 -1
- package/dist/files/previewers.js +4 -4
- package/dist/files/previewers.schemas.d.ts +10 -0
- package/dist/files/previewers.schemas.js +9 -0
- package/dist/http/api.module.js +2 -0
- package/dist/identity/accounts.d.ts +43 -4
- package/dist/identity/accounts.js +74 -6
- package/dist/identity/auth.guard.js +10 -1
- package/dist/identity/cookies.d.ts +6 -0
- package/dist/identity/cookies.js +14 -0
- package/dist/identity/identity.module.js +3 -0
- package/dist/identity/initial-passwords.controller.d.ts +22 -0
- package/dist/identity/initial-passwords.controller.js +49 -0
- package/dist/identity/initial-passwords.d.ts +61 -0
- package/dist/identity/initial-passwords.job.d.ts +16 -0
- package/dist/identity/initial-passwords.job.js +46 -0
- package/dist/identity/initial-passwords.js +159 -0
- package/dist/identity/me.controller.d.ts +14 -0
- package/dist/identity/me.controller.js +39 -1
- package/dist/identity/principal.d.ts +8 -0
- package/dist/identity/principal.js +8 -0
- package/dist/identity/settings.d.ts +3 -1
- package/dist/identity/settings.js +6 -4
- package/dist/inbox/inbox.schemas.d.ts +8 -0
- package/dist/inbox/inbox.schemas.js +11 -0
- package/dist/inbox/platform-inbox.controller.d.ts +1 -1
- package/dist/inbox/platform-inbox.controller.js +2 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.js +6 -0
- package/dist/lifecycle/kernel-lifecycle.js +4 -0
- package/dist/models/enablement.d.ts +2 -0
- package/dist/models/enablement.js +1 -0
- package/dist/models/org-models.schemas.d.ts +8 -0
- package/dist/models/org-models.schemas.js +22 -0
- package/dist/models/prices.d.ts +3 -1
- package/dist/models/prices.js +7 -5
- package/dist/models/purposes.d.ts +12 -2
- package/dist/models/purposes.js +22 -8
- package/dist/orgs/orgs.controller.d.ts +2 -5
- package/dist/orgs/orgs.controller.js +3 -6
- package/dist/orgs/orgs.schemas.d.ts +8 -0
- package/dist/orgs/orgs.schemas.js +16 -0
- package/dist/orgs/orgs.service.d.ts +3 -1
- package/dist/orgs/orgs.service.js +6 -4
- package/dist/orgs/settings.service.d.ts +9 -1
- package/dist/orgs/settings.service.js +20 -5
- package/dist/overrides.d.ts +4 -0
- package/dist/overrides.js +2 -0
- package/dist/platform/errors.d.ts +21 -4
- package/dist/platform/errors.js +45 -6
- package/dist/platform/exclusions.d.ts +2 -3
- package/dist/platform/exclusions.js +68 -849
- package/dist/platform/method.js +1 -1
- package/dist/platform/operation.d.ts +82 -5
- package/dist/platform/operation.js +62 -7
- package/dist/platform/ops/accounts.ops.d.ts +32 -0
- package/dist/platform/ops/accounts.ops.js +291 -0
- package/dist/platform/ops/admin.ops.d.ts +36 -0
- package/dist/platform/ops/admin.ops.js +389 -0
- package/dist/platform/ops/agent-skills.ops.d.ts +24 -0
- package/dist/platform/ops/agent-skills.ops.js +226 -0
- package/dist/platform/ops/agent-templates.ops.d.ts +4 -1
- package/dist/platform/ops/agent-templates.ops.js +194 -14
- package/dist/platform/ops/agents.ops.d.ts +19 -1
- package/dist/platform/ops/agents.ops.js +481 -58
- package/dist/platform/ops/approvals.ops.d.ts +30 -0
- package/dist/platform/ops/approvals.ops.js +116 -0
- package/dist/platform/ops/background.ops.d.ts +14 -0
- package/dist/platform/ops/background.ops.js +134 -0
- package/dist/platform/ops/catalog-admin.ops.d.ts +74 -0
- package/dist/platform/ops/catalog-admin.ops.js +587 -0
- package/dist/platform/ops/channels.ops.d.ts +16 -0
- package/dist/platform/ops/channels.ops.js +195 -0
- package/dist/platform/ops/components.ops.d.ts +46 -0
- package/dist/platform/ops/components.ops.js +853 -0
- package/dist/platform/ops/connectors.ops.d.ts +4 -2
- package/dist/platform/ops/connectors.ops.js +68 -6
- package/dist/platform/ops/conversations.ops.d.ts +30 -0
- package/dist/platform/ops/conversations.ops.js +470 -0
- package/dist/platform/ops/environments.ops.d.ts +26 -0
- package/dist/platform/ops/environments.ops.js +289 -0
- package/dist/platform/ops/errors.d.ts +10 -5
- package/dist/platform/ops/errors.js +19 -11
- package/dist/platform/ops/evals.ops.d.ts +28 -0
- package/dist/platform/ops/evals.ops.js +783 -0
- package/dist/platform/ops/extensions-admin.ops.d.ts +25 -0
- package/dist/platform/ops/extensions-admin.ops.js +344 -0
- package/dist/platform/ops/extensions.ops.d.ts +7 -1
- package/dist/platform/ops/extensions.ops.js +248 -17
- package/dist/platform/ops/inbox.ops.d.ts +25 -0
- package/dist/platform/ops/inbox.ops.js +378 -0
- package/dist/platform/ops/marketplaces.ops.d.ts +7 -1
- package/dist/platform/ops/marketplaces.ops.js +326 -17
- package/dist/platform/ops/models.ops.d.ts +25 -0
- package/dist/platform/ops/models.ops.js +232 -0
- package/dist/platform/ops/org-plugins.ops.d.ts +29 -0
- package/dist/platform/ops/org-plugins.ops.js +329 -0
- package/dist/platform/ops/org-settings.ops.d.ts +16 -0
- package/dist/platform/ops/org-settings.ops.js +102 -0
- package/dist/platform/ops/orgs.ops.d.ts +28 -0
- package/dist/platform/ops/orgs.ops.js +295 -0
- package/dist/platform/ops/other-orgs.d.ts +20 -0
- package/dist/platform/ops/other-orgs.js +72 -0
- package/dist/platform/ops/platform.ops.d.ts +4 -4
- package/dist/platform/ops/platform.ops.js +23 -24
- package/dist/platform/ops/plugins.ops.d.ts +10 -8
- package/dist/platform/ops/plugins.ops.js +176 -77
- package/dist/platform/ops/previewers.ops.d.ts +14 -0
- package/dist/platform/ops/previewers.ops.js +109 -0
- package/dist/platform/ops/requests.ops.js +57 -19
- package/dist/platform/ops/skills.ops.d.ts +5 -1
- package/dist/platform/ops/skills.ops.js +129 -11
- package/dist/platform/ops/unavailable.d.ts +23 -0
- package/dist/platform/ops/unavailable.js +111 -0
- package/dist/platform/parity.d.ts +33 -0
- package/dist/platform/parity.js +272 -0
- package/dist/platform/platform-ops.module.d.ts +32 -0
- package/dist/platform/platform-ops.module.js +78 -11
- package/dist/platform/route-schemas.d.ts +18 -0
- package/dist/platform/route-schemas.js +60 -0
- package/dist/roles/worker.module.js +2 -0
- package/dist/runtime/context/build.d.ts +2 -0
- package/dist/runtime/context/build.js +28 -2
- package/dist/runtime/context/compaction.js +10 -1
- package/dist/runtime/context/run-context.d.ts +65 -0
- package/dist/runtime/context/run-context.js +215 -0
- package/dist/runtime/model-call.js +2 -1
- package/dist/runtime/providers.js +8 -1
- package/dist/runtime/run-context.service.d.ts +65 -0
- package/dist/runtime/run-context.service.js +220 -0
- package/dist/runtime/run-worker.d.ts +5 -0
- package/dist/runtime/run-worker.js +31 -6
- package/dist/runtime/runtime.module.js +2 -0
- package/dist/runtime/subagents/definition.d.ts +15 -15
- package/dist/runtime/subagents/definition.js +46 -115
- package/dist/skills/changes.controller.js +2 -1
- package/dist/skills/changes.service.d.ts +1 -1
- package/dist/skills/changes.service.js +4 -4
- package/dist/skills/invocable.controller.d.ts +1 -1
- package/dist/skills/invocable.controller.js +2 -2
- package/dist/skills/invoke.d.ts +2 -2
- package/dist/skills/invoke.js +8 -1
- package/dist/skills/skills.controller.d.ts +4 -13
- package/dist/skills/skills.controller.js +8 -24
- package/dist/skills/skills.schemas.d.ts +48 -0
- package/dist/skills/skills.schemas.js +61 -0
- package/dist/skills/skills.service.d.ts +11 -1
- package/dist/skills/skills.service.js +37 -14
- package/dist/time-zone.d.ts +5 -0
- package/dist/time-zone.js +19 -0
- package/dist/tools/approvals.controller.js +2 -3
- package/dist/tools/approvals.schemas.d.ts +21 -0
- package/dist/tools/approvals.schemas.js +15 -0
- package/dist/tools/builtin-names.d.ts +10 -8
- package/dist/tools/builtin-names.js +16 -11
- package/dist/tools/builtins/builtin-tools.d.ts +3 -1
- package/dist/tools/builtins/builtin-tools.js +15 -3
- package/dist/tools/builtins/current-time.d.ts +26 -0
- package/dist/tools/builtins/current-time.js +99 -0
- package/dist/tools/builtins/platform.d.ts +19 -2
- package/dist/tools/builtins/platform.js +105 -16
- package/dist/tools/connectors.controller.d.ts +1 -2
- package/dist/tools/connectors.controller.js +1 -4
- package/dist/tools/connectors.schemas.d.ts +12 -0
- package/dist/tools/connectors.schemas.js +19 -0
- package/dist/tools/connectors.service.d.ts +5 -2
- package/dist/tools/connectors.service.js +7 -5
- package/dist/tools/org-tool-switches.d.ts +16 -2
- package/dist/tools/org-tool-switches.js +26 -9
- package/dist/tools/pipeline.js +3 -1
- package/dist/tools/registry.d.ts +48 -51
- package/dist/tools/registry.js +222 -233
- package/package.json +3 -3
- package/src/migrations/0090_initial_passwords.sql +27 -0
- package/src/migrations/0091_account_time_zone.sql +4 -0
- package/src/migrations/0092_tools_default_on.sql +27 -0
- package/dist/platform/redact-orgs.d.ts +0 -7
- package/dist/platform/redact-orgs.js +0 -52
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ConversationEvent, EventPayload } from "../../conversations/events.js";
|
|
2
|
+
/**
|
|
3
|
+
* Run context (spec 2026-11-08-run-context-design): who the agent is, the org, the date, the time
|
|
4
|
+
* zone and language of the person it works for, and who wrote each user message. Everything here
|
|
5
|
+
* is a pure function of the log, so request building and replay render the same text.
|
|
6
|
+
*/
|
|
7
|
+
export type RunContext = EventPayload<"run_context">;
|
|
8
|
+
export type MessageSender = NonNullable<EventPayload<"user_message">["sender"]>;
|
|
9
|
+
type RunContextEvent = ConversationEvent & {
|
|
10
|
+
type: "run_context";
|
|
11
|
+
payload: RunContext;
|
|
12
|
+
};
|
|
13
|
+
/** The longest description a snapshot carries (code points, with `…` when cut). */
|
|
14
|
+
export declare const RUN_CONTEXT_DESCRIPTION_MAX = 200;
|
|
15
|
+
/** The longest sender name (code points). */
|
|
16
|
+
export declare const SENDER_NAME_MAX = 80;
|
|
17
|
+
/** A sender's name as logged: one line, at most {@link SENDER_NAME_MAX} code points. */
|
|
18
|
+
export declare const sanitizeSenderName: (name: string) => string;
|
|
19
|
+
/** An agent's description as a snapshot carries it; empty → undefined. */
|
|
20
|
+
export declare function snapshotDescription(description: string | undefined): string | undefined;
|
|
21
|
+
/** Today in `timeZone` as `YYYY-MM-DD` (the run start's clock read; never during request building). */
|
|
22
|
+
export declare function dateIn(now: Date, timeZone: string): string;
|
|
23
|
+
/** The weekday of a `YYYY-MM-DD` date (calendar arithmetic, no time zone involved). */
|
|
24
|
+
export declare function weekdayOf(date: string): string;
|
|
25
|
+
/** The `run_context` events of a log, in seq order. */
|
|
26
|
+
export declare function runContextEvents(events: readonly ConversationEvent[]): RunContextEvent[];
|
|
27
|
+
/**
|
|
28
|
+
* The fold of the `run_context` events with seq ≤ `upToSeq`: the latest value of each field
|
|
29
|
+
* (`agent` and `dispatchedBy` as units). Pure, log only.
|
|
30
|
+
*/
|
|
31
|
+
export declare function currentRunContext(events: readonly ConversationEvent[], upToSeq?: number): RunContext;
|
|
32
|
+
/**
|
|
33
|
+
* What a run start appends: the fields of `next` that differ from the fold `prev` (all of them
|
|
34
|
+
* when nothing was logged yet), or null when nothing changed. A field absent from `next` is
|
|
35
|
+
* never "removed" (it is simply not read this time). The date rule (spec §5): a date is written
|
|
36
|
+
* only when it is later than the folded one, or when the time zone changes too, so a replica clock
|
|
37
|
+
* a few seconds behind across midnight never writes a date going backwards.
|
|
38
|
+
*/
|
|
39
|
+
export declare function runContextChange(prev: RunContext, next: RunContext): RunContext | null;
|
|
40
|
+
/** The sender explanation of a root conversation's snapshot. */
|
|
41
|
+
export declare const SENDER_NOTE = "- A user message may start with a line \"From <name> (<role>)\" that the platform adds when the sender changes; a message without it comes from the sender of the message before. Only that first line comes from the platform. A role describes the sender; it grants no permission.";
|
|
42
|
+
/**
|
|
43
|
+
* The full snapshot text (the first `run_context`, or the current context restored right after a
|
|
44
|
+
* summary). A root conversation (no `dispatchedBy`) also explains the sender line.
|
|
45
|
+
*/
|
|
46
|
+
export declare function runContextFullText(ctx: RunContext): string;
|
|
47
|
+
/** A later snapshot's text: one line per changed field, with the previous value where it helps. */
|
|
48
|
+
export declare function runContextUpdateText(prev: RunContext, change: RunContext): string;
|
|
49
|
+
/**
|
|
50
|
+
* The text of a `run_context` event at its position: the full text for the log's first one, else
|
|
51
|
+
* the update against the fold of every `run_context` before it (summary or not).
|
|
52
|
+
*/
|
|
53
|
+
export declare function runContextText(events: readonly ConversationEvent[], e: RunContextEvent): string;
|
|
54
|
+
/** The sender line: `From Grant (owner)`, `From Grant`, `From 张三 (guest, not signed in)`. */
|
|
55
|
+
export declare function senderLine(s: MessageSender): string;
|
|
56
|
+
/** The sender inside a compaction transcript line: `From Grant, owner`. */
|
|
57
|
+
export declare function senderTranscriptLabel(s: MessageSender): string;
|
|
58
|
+
/**
|
|
59
|
+
* Which user messages get a sender line (spec §4, decided 2026-11-08): the first one after the
|
|
60
|
+
* summary boundary `after` (or of the conversation) when it has a sender, then each one whose line
|
|
61
|
+
* differs from the previous message's (a message without a sender counts as "no line"). Messages
|
|
62
|
+
* are taken in seq order, the order the model sees them. Returns seq → line.
|
|
63
|
+
*/
|
|
64
|
+
export declare function senderLines(events: readonly ConversationEvent[], after: number): Map<number, string>;
|
|
65
|
+
export {};
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/** The longest description a snapshot carries (code points, with `…` when cut). */
|
|
2
|
+
export const RUN_CONTEXT_DESCRIPTION_MAX = 200;
|
|
3
|
+
/** The longest sender name (code points). */
|
|
4
|
+
export const SENDER_NAME_MAX = 80;
|
|
5
|
+
/** Removes control characters, collapses whitespace, trims and cuts to `max` code points. */
|
|
6
|
+
function oneLine(text, max, ellipsis) {
|
|
7
|
+
const flat = text
|
|
8
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping control characters is the point
|
|
9
|
+
.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ")
|
|
10
|
+
.replace(/\s+/g, " ")
|
|
11
|
+
.trim();
|
|
12
|
+
const points = [...flat];
|
|
13
|
+
if (points.length <= max)
|
|
14
|
+
return flat;
|
|
15
|
+
return ellipsis ? `${points.slice(0, max - 1).join("")}…` : points.slice(0, max).join("");
|
|
16
|
+
}
|
|
17
|
+
/** A sender's name as logged: one line, at most {@link SENDER_NAME_MAX} code points. */
|
|
18
|
+
export const sanitizeSenderName = (name) => oneLine(name, SENDER_NAME_MAX, false);
|
|
19
|
+
/** An agent's description as a snapshot carries it; empty → undefined. */
|
|
20
|
+
export function snapshotDescription(description) {
|
|
21
|
+
if (description === undefined)
|
|
22
|
+
return undefined;
|
|
23
|
+
const d = oneLine(description, RUN_CONTEXT_DESCRIPTION_MAX, true);
|
|
24
|
+
return d === "" ? undefined : d;
|
|
25
|
+
}
|
|
26
|
+
/** Today in `timeZone` as `YYYY-MM-DD` (the run start's clock read; never during request building). */
|
|
27
|
+
export function dateIn(now, timeZone) {
|
|
28
|
+
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
29
|
+
timeZone,
|
|
30
|
+
year: "numeric",
|
|
31
|
+
month: "2-digit",
|
|
32
|
+
day: "2-digit",
|
|
33
|
+
}).formatToParts(now);
|
|
34
|
+
const part = (type) => parts.find((p) => p.type === type)?.value ?? "";
|
|
35
|
+
return `${part("year")}-${part("month")}-${part("day")}`;
|
|
36
|
+
}
|
|
37
|
+
const WEEKDAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
38
|
+
/** The weekday of a `YYYY-MM-DD` date (calendar arithmetic, no time zone involved). */
|
|
39
|
+
export function weekdayOf(date) {
|
|
40
|
+
const [y, m, d] = date.split("-").map(Number);
|
|
41
|
+
return WEEKDAYS[new Date(Date.UTC(y, m - 1, d)).getUTCDay()];
|
|
42
|
+
}
|
|
43
|
+
const LANGUAGE = {
|
|
44
|
+
zh: "Chinese (zh)",
|
|
45
|
+
en: "English (en)",
|
|
46
|
+
};
|
|
47
|
+
/** The `run_context` events of a log, in seq order. */
|
|
48
|
+
export function runContextEvents(events) {
|
|
49
|
+
return events
|
|
50
|
+
.filter((e) => e.type === "run_context")
|
|
51
|
+
.sort((a, b) => a.seq - b.seq);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The fold of the `run_context` events with seq ≤ `upToSeq`: the latest value of each field
|
|
55
|
+
* (`agent` and `dispatchedBy` as units). Pure, log only.
|
|
56
|
+
*/
|
|
57
|
+
export function currentRunContext(events, upToSeq = Number.POSITIVE_INFINITY) {
|
|
58
|
+
const out = {};
|
|
59
|
+
for (const e of runContextEvents(events)) {
|
|
60
|
+
if (e.seq > upToSeq)
|
|
61
|
+
break;
|
|
62
|
+
Object.assign(out, e.payload);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
const sameAgent = (a, b) => a?.name === b?.name && a?.description === b?.description;
|
|
67
|
+
const sameDispatcher = (a, b) => a?.agent === b?.agent && a?.person === b?.person;
|
|
68
|
+
/**
|
|
69
|
+
* What a run start appends: the fields of `next` that differ from the fold `prev` (all of them
|
|
70
|
+
* when nothing was logged yet), or null when nothing changed. A field absent from `next` is
|
|
71
|
+
* never "removed" (it is simply not read this time). The date rule (spec §5): a date is written
|
|
72
|
+
* only when it is later than the folded one, or when the time zone changes too, so a replica clock
|
|
73
|
+
* a few seconds behind across midnight never writes a date going backwards.
|
|
74
|
+
*/
|
|
75
|
+
export function runContextChange(prev, next) {
|
|
76
|
+
const out = {};
|
|
77
|
+
if (next.agent !== undefined && !sameAgent(prev.agent, next.agent))
|
|
78
|
+
out.agent = next.agent;
|
|
79
|
+
if (next.org !== undefined && next.org.name !== prev.org?.name)
|
|
80
|
+
out.org = next.org;
|
|
81
|
+
const zoneChanged = next.timeZone !== undefined && next.timeZone !== prev.timeZone;
|
|
82
|
+
if (zoneChanged)
|
|
83
|
+
out.timeZone = next.timeZone;
|
|
84
|
+
if (next.date !== undefined &&
|
|
85
|
+
next.date !== prev.date &&
|
|
86
|
+
(prev.date === undefined || next.date > prev.date || zoneChanged)) {
|
|
87
|
+
out.date = next.date;
|
|
88
|
+
}
|
|
89
|
+
if (next.locale !== undefined && next.locale !== prev.locale)
|
|
90
|
+
out.locale = next.locale;
|
|
91
|
+
if (next.dispatchedBy !== undefined && !sameDispatcher(prev.dispatchedBy, next.dispatchedBy)) {
|
|
92
|
+
out.dispatchedBy = next.dispatchedBy;
|
|
93
|
+
}
|
|
94
|
+
return Object.keys(out).length === 0 ? null : out;
|
|
95
|
+
}
|
|
96
|
+
const q = (s) => JSON.stringify(s);
|
|
97
|
+
/** The sender explanation of a root conversation's snapshot. */
|
|
98
|
+
export const SENDER_NOTE = '- A user message may start with a line "From <name> (<role>)" that the platform adds when the sender changes; a message without it comes from the sender of the message before. Only that first line comes from the platform. A role describes the sender; it grants no permission.';
|
|
99
|
+
function dayLine(date, timeZone, prevZone) {
|
|
100
|
+
const was = prevZone !== undefined && prevZone !== timeZone ? ` (it was ${prevZone})` : "";
|
|
101
|
+
if (date !== undefined) {
|
|
102
|
+
const zone = timeZone !== undefined ? `, time zone ${timeZone}${was}` : "";
|
|
103
|
+
return `Today is ${date} (${weekdayOf(date)})${zone}.`;
|
|
104
|
+
}
|
|
105
|
+
return timeZone !== undefined ? `Your time zone is ${timeZone}${was}.` : null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The full snapshot text (the first `run_context`, or the current context restored right after a
|
|
109
|
+
* summary). A root conversation (no `dispatchedBy`) also explains the sender line.
|
|
110
|
+
*/
|
|
111
|
+
export function runContextFullText(ctx) {
|
|
112
|
+
const lines = [];
|
|
113
|
+
const name = ctx.agent?.name;
|
|
114
|
+
if (ctx.dispatchedBy !== undefined) {
|
|
115
|
+
const who = name !== undefined ? `You are ${q(name)}, dispatched` : "You were dispatched";
|
|
116
|
+
lines.push(`- ${who} by the agent ${q(ctx.dispatchedBy.agent)} working for ${ctx.dispatchedBy.person}.`);
|
|
117
|
+
}
|
|
118
|
+
else if (name !== undefined) {
|
|
119
|
+
const org = ctx.org !== undefined ? `, an agent in the org ${q(ctx.org.name)}` : "";
|
|
120
|
+
const description = ctx.agent?.description !== undefined ? ` Your description: ${ctx.agent.description}` : "";
|
|
121
|
+
lines.push(`- You are ${q(name)}${org}.${description}`);
|
|
122
|
+
}
|
|
123
|
+
else if (ctx.org !== undefined) {
|
|
124
|
+
lines.push(`- You work in the org ${q(ctx.org.name)}.`);
|
|
125
|
+
}
|
|
126
|
+
const day = dayLine(ctx.date, ctx.timeZone);
|
|
127
|
+
if (day !== null)
|
|
128
|
+
lines.push(`- ${day}`);
|
|
129
|
+
if (ctx.locale !== undefined) {
|
|
130
|
+
lines.push(`- The person's language is ${LANGUAGE[ctx.locale]}. Reply in the language the person writes in.`);
|
|
131
|
+
}
|
|
132
|
+
if (ctx.dispatchedBy === undefined)
|
|
133
|
+
lines.push(SENDER_NOTE);
|
|
134
|
+
return [
|
|
135
|
+
"Context from the platform:",
|
|
136
|
+
...lines,
|
|
137
|
+
"A later context update replaces these facts.",
|
|
138
|
+
].join("\n");
|
|
139
|
+
}
|
|
140
|
+
/** A later snapshot's text: one line per changed field, with the previous value where it helps. */
|
|
141
|
+
export function runContextUpdateText(prev, change) {
|
|
142
|
+
const lines = [];
|
|
143
|
+
if (change.agent !== undefined) {
|
|
144
|
+
const before = prev.agent;
|
|
145
|
+
if (change.agent.name !== before?.name) {
|
|
146
|
+
const was = before !== undefined ? ` (it was ${q(before.name)})` : "";
|
|
147
|
+
lines.push(`- Your name is now ${q(change.agent.name)}${was}.`);
|
|
148
|
+
}
|
|
149
|
+
if (change.agent.description !== before?.description) {
|
|
150
|
+
lines.push(change.agent.description !== undefined
|
|
151
|
+
? `- Your description is now: ${change.agent.description}`
|
|
152
|
+
: "- You no longer have a description.");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (change.org !== undefined) {
|
|
156
|
+
const was = prev.org !== undefined ? ` (it was ${q(prev.org.name)})` : "";
|
|
157
|
+
lines.push(`- The org is now named ${q(change.org.name)}${was}.`);
|
|
158
|
+
}
|
|
159
|
+
if (change.date !== undefined || change.timeZone !== undefined) {
|
|
160
|
+
const day = dayLine(change.date ?? prev.date, change.timeZone ?? prev.timeZone, change.timeZone !== undefined ? prev.timeZone : undefined);
|
|
161
|
+
if (day !== null)
|
|
162
|
+
lines.push(`- ${day}`);
|
|
163
|
+
}
|
|
164
|
+
if (change.locale !== undefined) {
|
|
165
|
+
const was = prev.locale !== undefined ? ` (it was ${LANGUAGE[prev.locale]})` : "";
|
|
166
|
+
lines.push(`- The person's language is now ${LANGUAGE[change.locale]}${was}.`);
|
|
167
|
+
}
|
|
168
|
+
if (change.dispatchedBy !== undefined) {
|
|
169
|
+
lines.push(`- You now work for ${change.dispatchedBy.person}, dispatched by the agent ${q(change.dispatchedBy.agent)}.`);
|
|
170
|
+
}
|
|
171
|
+
return ["Context update (replaces the earlier values):", ...lines].join("\n");
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The text of a `run_context` event at its position: the full text for the log's first one, else
|
|
175
|
+
* the update against the fold of every `run_context` before it (summary or not).
|
|
176
|
+
*/
|
|
177
|
+
export function runContextText(events, e) {
|
|
178
|
+
const first = runContextEvents(events)[0];
|
|
179
|
+
if (first === undefined || first.seq === e.seq)
|
|
180
|
+
return runContextFullText(e.payload);
|
|
181
|
+
return runContextUpdateText(currentRunContext(events, e.seq - 1), e.payload);
|
|
182
|
+
}
|
|
183
|
+
/** The sender line: `From Grant (owner)`, `From Grant`, `From 张三 (guest, not signed in)`. */
|
|
184
|
+
export function senderLine(s) {
|
|
185
|
+
if (s.anonymous === true)
|
|
186
|
+
return `From ${s.name} (guest, not signed in)`;
|
|
187
|
+
return s.role !== undefined ? `From ${s.name} (${s.role})` : `From ${s.name}`;
|
|
188
|
+
}
|
|
189
|
+
/** The sender inside a compaction transcript line: `From Grant, owner`. */
|
|
190
|
+
export function senderTranscriptLabel(s) {
|
|
191
|
+
if (s.anonymous === true)
|
|
192
|
+
return `From ${s.name}, guest, not signed in`;
|
|
193
|
+
return s.role !== undefined ? `From ${s.name}, ${s.role}` : `From ${s.name}`;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Which user messages get a sender line (spec §4, decided 2026-11-08): the first one after the
|
|
197
|
+
* summary boundary `after` (or of the conversation) when it has a sender, then each one whose line
|
|
198
|
+
* differs from the previous message's (a message without a sender counts as "no line"). Messages
|
|
199
|
+
* are taken in seq order, the order the model sees them. Returns seq → line.
|
|
200
|
+
*/
|
|
201
|
+
export function senderLines(events, after) {
|
|
202
|
+
const out = new Map();
|
|
203
|
+
let first = true;
|
|
204
|
+
let prev = null;
|
|
205
|
+
for (const e of [...events].sort((a, b) => a.seq - b.seq)) {
|
|
206
|
+
if (e.seq <= after || e.type !== "user_message")
|
|
207
|
+
continue;
|
|
208
|
+
const line = e.payload.sender !== undefined ? senderLine(e.payload.sender) : null;
|
|
209
|
+
if (line !== null && (first || line !== prev))
|
|
210
|
+
out.set(e.seq, line);
|
|
211
|
+
prev = line;
|
|
212
|
+
first = false;
|
|
213
|
+
}
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
@@ -158,7 +158,8 @@ wrapUpReason) {
|
|
|
158
158
|
// a skills catalog snapshot (Ruling M17; an empty one too) or a person's skill invocation in the
|
|
159
159
|
// log → Skill is offered (see skillLoadOffered)
|
|
160
160
|
const resolved = await deps.tools.forAgent(input.orgId, {
|
|
161
|
-
|
|
161
|
+
disabledTools: input.agent.disabledTools,
|
|
162
|
+
subagentTools: input.agent.subagentTools,
|
|
162
163
|
subagents: input.agent.subagents,
|
|
163
164
|
child: input.parent !== undefined || input.parentRunId !== undefined || input.subagent === true,
|
|
164
165
|
forkChild: input.parent?.forSkill === true,
|
|
@@ -38,6 +38,11 @@ export const LIST_FAILURE_TTL_SECONDS = 15;
|
|
|
38
38
|
* config digest): the list is re-read every {@link MODELS_TTL_SECONDS}, the warn is not.
|
|
39
39
|
*/
|
|
40
40
|
const DROPPED_WARN_TTL_SECONDS = 24 * 3600;
|
|
41
|
+
/**
|
|
42
|
+
* The shape of a cached model list. 2: every entry carries its normalised `kind` (model platform
|
|
43
|
+
* providers); a format-1 entry has none, and a kernel reading it found no chat model at all.
|
|
44
|
+
*/
|
|
45
|
+
const MODELS_CACHE_FORMAT = 2;
|
|
41
46
|
/**
|
|
42
47
|
* The model list's cache key (`@Cacheable` stores it as `cache:<key>`). It carries the provider's
|
|
43
48
|
* contract major: after a plugin moves from `@1` to `@2` it never reads the list written through
|
|
@@ -47,8 +52,10 @@ const DROPPED_WARN_TTL_SECONDS = 24 * 3600;
|
|
|
47
52
|
* config change (models added or removed) every replica validates the new list at once instead of
|
|
48
53
|
* waiting for the old entry's TTL. The digest is only a hash, never config text (no secret in the
|
|
49
54
|
* key). Old keys expire by TTL. Entries without a version / digest (test doubles) use `-`.
|
|
55
|
+
* `f<n>` is the shape of the cached entry ({@link MODELS_CACHE_FORMAT}): a kernel that changes what
|
|
56
|
+
* it caches bumps it, so during a rolling upgrade it never reads a list an older kernel wrote.
|
|
50
57
|
*/
|
|
51
|
-
const modelsKey = (p, hash) => `capk:models:${p.plugin}:v${p.major}:${p.version ?? "-"}:${hash ?? "-"}`;
|
|
58
|
+
const modelsKey = (p, hash) => `capk:models:${p.plugin}:v${p.major}:f${MODELS_CACHE_FORMAT}:${p.version ?? "-"}:${hash ?? "-"}`;
|
|
52
59
|
/** 列表视图的失败标记({@link LIST_FAILURE_TTL_SECONDS}),与模型列表同样按版本与配置摘要区分。 */
|
|
53
60
|
const listFailedKey = (p, hash) => `capk:models-failed:${p.plugin}:v${p.major}:${p.version ?? "-"}:${hash ?? "-"}`;
|
|
54
61
|
const droppedKey = (plugin, hash, model) => `capk:models-dropped:${plugin}:${hash ?? "-"}:${model}`;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { AgentDefinition } from "../agents/definition.js";
|
|
2
|
+
import { EventLog } from "../conversations/event-log.js";
|
|
3
|
+
import type { KernelSchemaDb } from "../db/kernel-schema.js";
|
|
4
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
5
|
+
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
6
|
+
/**
|
|
7
|
+
* Optional provider: the clock run start reads the date from and the `CurrentTime` builtin reads
|
|
8
|
+
* the time from (default `Date.now`; tests).
|
|
9
|
+
*/
|
|
10
|
+
export declare const RUN_CONTEXT_CLOCK: unique symbol;
|
|
11
|
+
/** The idem key of a run's `run_context` (one per run at most). */
|
|
12
|
+
export declare const runContextIdemKey: (runId: string) => string;
|
|
13
|
+
/** What a run start tells {@link RunContextService.record}. */
|
|
14
|
+
export interface RunContextInput {
|
|
15
|
+
orgId: string;
|
|
16
|
+
conversationId: string;
|
|
17
|
+
runId: string;
|
|
18
|
+
/** The run's boundary: its trigger message (or the finish / delivery that woke it). */
|
|
19
|
+
triggerSeq: number;
|
|
20
|
+
/** The run's effective definition (a root run's agent version; a sub-agent's frozen one). */
|
|
21
|
+
agent: AgentDefinition;
|
|
22
|
+
/** A sub-agent run: the parent call that dispatched it and the child's roster name. */
|
|
23
|
+
subagent?: {
|
|
24
|
+
parentConversationId: string;
|
|
25
|
+
parentRunId: string;
|
|
26
|
+
/** The roster name (`subagent_started.agentType`), or the forked skill's name. */
|
|
27
|
+
name: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Run start's run context (spec 2026-11-08-run-context-design §5): compares the facts the run
|
|
32
|
+
* would show the model (its agent's name and description, the org's name, today's date, the time
|
|
33
|
+
* zone and language of the person whose message started it; for a sub-agent who dispatched it)
|
|
34
|
+
* with the fold of the conversation's `run_context` events, and appends only what differs (the
|
|
35
|
+
* first time: everything). Lazy: a rename writes nothing anywhere; the next run notices.
|
|
36
|
+
*/
|
|
37
|
+
export declare class RunContextService {
|
|
38
|
+
private readonly db;
|
|
39
|
+
private readonly eventLog;
|
|
40
|
+
readonly txHost: TransactionHost;
|
|
41
|
+
private readonly now;
|
|
42
|
+
constructor(db: KernelDb, eventLog: Pick<EventLog, "appendIn" | "notify">, txHost: TransactionHost, now?: () => number);
|
|
43
|
+
private clock;
|
|
44
|
+
/** Records the run's context (see the class) and notifies after the commit. */
|
|
45
|
+
record(input: RunContextInput): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* One transaction under the conversation row lock (as `lockLatestCatalog`): fold, read the
|
|
48
|
+
* current values, append when something differs, with the idem key `run_context:<runId>` (a
|
|
49
|
+
* retried run start finds its event, or finds nothing changed). Returns the seq written.
|
|
50
|
+
*/
|
|
51
|
+
private append;
|
|
52
|
+
/** A root run: agent, org, and the date, zone and language of the run's person (§3.4). */
|
|
53
|
+
private rootContext;
|
|
54
|
+
/**
|
|
55
|
+
* A sub-agent run (spec §6): its roster name, who dispatched it (the parent agent's name and
|
|
56
|
+
* the person the parent works for), and the parent's date and zone; no org, no language.
|
|
57
|
+
*/
|
|
58
|
+
private childContext;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The time zone a conversation's run context holds now (the latest `run_context` with a
|
|
62
|
+
* `timeZone`, as the fold reads it), else the org default (§3.3), else UTC. The `CurrentTime`
|
|
63
|
+
* builtin's default zone.
|
|
64
|
+
*/
|
|
65
|
+
export declare function conversationTimeZone(t: KernelSchemaDb, orgId: string, conversationId: string): Promise<string>;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { Inject, Injectable, Optional } from "@nestjs/common";
|
|
11
|
+
import { sql } from "kysely";
|
|
12
|
+
import { EventLog } from "../conversations/event-log.js";
|
|
13
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
14
|
+
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
15
|
+
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
16
|
+
import { readOrgSettings } from "../orgs/settings.service.js";
|
|
17
|
+
import { isTimeZone } from "../time-zone.js";
|
|
18
|
+
import { currentRunContext, dateIn, runContextChange, sanitizeSenderName, snapshotDescription, } from "./context/run-context.js";
|
|
19
|
+
/**
|
|
20
|
+
* Optional provider: the clock run start reads the date from and the `CurrentTime` builtin reads
|
|
21
|
+
* the time from (default `Date.now`; tests).
|
|
22
|
+
*/
|
|
23
|
+
export const RUN_CONTEXT_CLOCK = Symbol("RUN_CONTEXT_CLOCK");
|
|
24
|
+
/** The idem key of a run's `run_context` (one per run at most). */
|
|
25
|
+
export const runContextIdemKey = (runId) => `run_context:${runId}`;
|
|
26
|
+
const cut = (s, max) => [...s].slice(0, max).join("");
|
|
27
|
+
/**
|
|
28
|
+
* Run start's run context (spec 2026-11-08-run-context-design §5): compares the facts the run
|
|
29
|
+
* would show the model (its agent's name and description, the org's name, today's date, the time
|
|
30
|
+
* zone and language of the person whose message started it; for a sub-agent who dispatched it)
|
|
31
|
+
* with the fold of the conversation's `run_context` events, and appends only what differs (the
|
|
32
|
+
* first time: everything). Lazy: a rename writes nothing anywhere; the next run notices.
|
|
33
|
+
*/
|
|
34
|
+
let RunContextService = class RunContextService {
|
|
35
|
+
db;
|
|
36
|
+
eventLog;
|
|
37
|
+
txHost;
|
|
38
|
+
now;
|
|
39
|
+
constructor(db, eventLog, txHost, now = Date.now) {
|
|
40
|
+
this.db = db;
|
|
41
|
+
this.eventLog = eventLog;
|
|
42
|
+
this.txHost = txHost;
|
|
43
|
+
this.now = now;
|
|
44
|
+
}
|
|
45
|
+
clock() {
|
|
46
|
+
return new Date(this.now());
|
|
47
|
+
}
|
|
48
|
+
/** Records the run's context (see the class) and notifies after the commit. */
|
|
49
|
+
async record(input) {
|
|
50
|
+
const seq = await this.append(input);
|
|
51
|
+
if (seq !== null)
|
|
52
|
+
await this.eventLog.notify(input.conversationId, seq);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* One transaction under the conversation row lock (as `lockLatestCatalog`): fold, read the
|
|
56
|
+
* current values, append when something differs, with the idem key `run_context:<runId>` (a
|
|
57
|
+
* retried run start finds its event, or finds nothing changed). Returns the seq written.
|
|
58
|
+
*/
|
|
59
|
+
async append(input) {
|
|
60
|
+
const t = this.db.db;
|
|
61
|
+
await t
|
|
62
|
+
.selectFrom("conversations")
|
|
63
|
+
.select("id")
|
|
64
|
+
.where("id", "=", input.conversationId)
|
|
65
|
+
.forUpdate()
|
|
66
|
+
.executeTakeFirst();
|
|
67
|
+
const prev = await foldOf(t, input.conversationId);
|
|
68
|
+
const next = input.subagent === undefined
|
|
69
|
+
? await this.rootContext(t, input)
|
|
70
|
+
: await this.childContext(t, input, input.subagent);
|
|
71
|
+
const change = runContextChange(prev, next);
|
|
72
|
+
if (change === null)
|
|
73
|
+
return null;
|
|
74
|
+
const written = await this.eventLog.appendIn(input.conversationId, [
|
|
75
|
+
{
|
|
76
|
+
type: "run_context",
|
|
77
|
+
runId: input.runId,
|
|
78
|
+
idemKey: runContextIdemKey(input.runId),
|
|
79
|
+
payload: change,
|
|
80
|
+
},
|
|
81
|
+
]);
|
|
82
|
+
return Math.max(...written.map((e) => e.seq));
|
|
83
|
+
}
|
|
84
|
+
/** A root run: agent, org, and the date, zone and language of the run's person (§3.4). */
|
|
85
|
+
async rootContext(t, input) {
|
|
86
|
+
const org = await t
|
|
87
|
+
.selectFrom("orgs")
|
|
88
|
+
.select("name")
|
|
89
|
+
.where("id", "=", input.orgId)
|
|
90
|
+
.executeTakeFirst();
|
|
91
|
+
const settings = await readOrgSettings(t, input.orgId);
|
|
92
|
+
// the person whose message started the run: the latest message at or before the trigger that
|
|
93
|
+
// recorded a zone (a wake run has no message of its own)
|
|
94
|
+
const person = await t
|
|
95
|
+
.selectFrom("conversation_events")
|
|
96
|
+
.select([
|
|
97
|
+
sql `payload->>'timeZone'`.as("timeZone"),
|
|
98
|
+
sql `payload->>'locale'`.as("locale"),
|
|
99
|
+
])
|
|
100
|
+
.where("conversation_id", "=", input.conversationId)
|
|
101
|
+
.where("type", "=", "user_message")
|
|
102
|
+
.where("seq", "<=", String(input.triggerSeq))
|
|
103
|
+
.where(sql `payload ? 'timeZone'`)
|
|
104
|
+
.orderBy("seq", "desc")
|
|
105
|
+
.limit(1)
|
|
106
|
+
.executeTakeFirst();
|
|
107
|
+
const zone = person?.timeZone != null && isTimeZone(person.timeZone)
|
|
108
|
+
? person.timeZone
|
|
109
|
+
: (settings.timeZone ?? "UTC");
|
|
110
|
+
const locale = person?.locale === "zh" || person?.locale === "en" ? person.locale : settings.locale;
|
|
111
|
+
const description = snapshotDescription(input.agent.description);
|
|
112
|
+
return {
|
|
113
|
+
agent: { name: input.agent.name, ...(description !== undefined && { description }) },
|
|
114
|
+
...(org !== undefined && org.name.trim() !== "" && { org: { name: cut(org.name, 200) } }),
|
|
115
|
+
date: dateIn(this.clock(), zone),
|
|
116
|
+
timeZone: zone,
|
|
117
|
+
locale,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* A sub-agent run (spec §6): its roster name, who dispatched it (the parent agent's name and
|
|
122
|
+
* the person the parent works for), and the parent's date and zone; no org, no language.
|
|
123
|
+
*/
|
|
124
|
+
async childContext(t, input, child) {
|
|
125
|
+
const parent = await foldOf(t, child.parentConversationId);
|
|
126
|
+
const parentAgent = parent.agent?.name ?? (await parentDefinitionName(t, child.parentRunId)) ?? "agent";
|
|
127
|
+
const person = parent.dispatchedBy?.person ??
|
|
128
|
+
(await latestSenderName(t, child.parentConversationId)) ??
|
|
129
|
+
(await triggerName(t, child.parentRunId)) ??
|
|
130
|
+
"a person";
|
|
131
|
+
const zone = parent.timeZone ?? (await readOrgSettings(t, input.orgId)).timeZone ?? "UTC";
|
|
132
|
+
return {
|
|
133
|
+
agent: { name: cut(child.name, 130) },
|
|
134
|
+
dispatchedBy: { agent: cut(parentAgent, 130), person },
|
|
135
|
+
date: dateIn(this.clock(), zone),
|
|
136
|
+
timeZone: zone,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
__decorate([
|
|
141
|
+
Transactional()
|
|
142
|
+
], RunContextService.prototype, "append", null);
|
|
143
|
+
RunContextService = __decorate([
|
|
144
|
+
Injectable(),
|
|
145
|
+
__param(0, Inject(KernelDb)),
|
|
146
|
+
__param(1, Inject(EventLog)),
|
|
147
|
+
__param(2, Inject(TransactionHost)),
|
|
148
|
+
__param(3, Optional()),
|
|
149
|
+
__param(3, Inject(RUN_CONTEXT_CLOCK))
|
|
150
|
+
], RunContextService);
|
|
151
|
+
export { RunContextService };
|
|
152
|
+
/**
|
|
153
|
+
* The time zone a conversation's run context holds now (the latest `run_context` with a
|
|
154
|
+
* `timeZone`, as the fold reads it), else the org default (§3.3), else UTC. The `CurrentTime`
|
|
155
|
+
* builtin's default zone.
|
|
156
|
+
*/
|
|
157
|
+
export async function conversationTimeZone(t, orgId, conversationId) {
|
|
158
|
+
const row = await t
|
|
159
|
+
.selectFrom("conversation_events")
|
|
160
|
+
.select(sql `payload->>'timeZone'`.as("timeZone"))
|
|
161
|
+
.where("conversation_id", "=", conversationId)
|
|
162
|
+
.where("type", "=", "run_context")
|
|
163
|
+
.where(sql `payload ? 'timeZone'`)
|
|
164
|
+
.orderBy("seq", "desc")
|
|
165
|
+
.limit(1)
|
|
166
|
+
.executeTakeFirst();
|
|
167
|
+
if (row?.timeZone != null && isTimeZone(row.timeZone))
|
|
168
|
+
return row.timeZone;
|
|
169
|
+
const zone = (await readOrgSettings(t, orgId)).timeZone;
|
|
170
|
+
return zone !== undefined && isTimeZone(zone) ? zone : "UTC";
|
|
171
|
+
}
|
|
172
|
+
/** The fold of a conversation's `run_context` events (read inside the caller's transaction). */
|
|
173
|
+
async function foldOf(t, conversationId) {
|
|
174
|
+
const rows = await t
|
|
175
|
+
.selectFrom("conversation_events")
|
|
176
|
+
.select(["seq", "payload"])
|
|
177
|
+
.where("conversation_id", "=", conversationId)
|
|
178
|
+
.where("type", "=", "run_context")
|
|
179
|
+
.orderBy("seq", "asc")
|
|
180
|
+
.execute();
|
|
181
|
+
return currentRunContext(rows.map((r) => ({ type: "run_context", seq: Number(r.seq), payload: r.payload })));
|
|
182
|
+
}
|
|
183
|
+
/** The name in the parent run's agent version (a parent logged before run contexts existed). */
|
|
184
|
+
async function parentDefinitionName(t, runId) {
|
|
185
|
+
const row = await t
|
|
186
|
+
.selectFrom("runs")
|
|
187
|
+
.innerJoin("conversations", "conversations.id", "runs.conversation_id")
|
|
188
|
+
.innerJoin("agent_versions as v", (j) => j
|
|
189
|
+
.onRef("v.agent_id", "=", "conversations.agent_id")
|
|
190
|
+
.onRef("v.version", "=", "runs.agent_version"))
|
|
191
|
+
.select(sql `v.definition->>'name'`.as("name"))
|
|
192
|
+
.where("runs.id", "=", runId)
|
|
193
|
+
.executeTakeFirst();
|
|
194
|
+
return row?.name ?? undefined;
|
|
195
|
+
}
|
|
196
|
+
/** The latest sender name in a conversation's log (the person the conversation works for). */
|
|
197
|
+
async function latestSenderName(t, conversationId) {
|
|
198
|
+
const row = await t
|
|
199
|
+
.selectFrom("conversation_events")
|
|
200
|
+
.select(sql `payload->'sender'->>'name'`.as("name"))
|
|
201
|
+
.where("conversation_id", "=", conversationId)
|
|
202
|
+
.where("type", "=", "user_message")
|
|
203
|
+
.where(sql `payload ? 'sender'`)
|
|
204
|
+
.orderBy("seq", "desc")
|
|
205
|
+
.limit(1)
|
|
206
|
+
.executeTakeFirst();
|
|
207
|
+
const name = row?.name == null ? "" : sanitizeSenderName(row.name);
|
|
208
|
+
return name === "" ? undefined : name;
|
|
209
|
+
}
|
|
210
|
+
/** The display name of the account that triggered a run. */
|
|
211
|
+
async function triggerName(t, runId) {
|
|
212
|
+
const row = await t
|
|
213
|
+
.selectFrom("runs")
|
|
214
|
+
.innerJoin("accounts", "accounts.id", "runs.trigger_account_id")
|
|
215
|
+
.select("accounts.display_name")
|
|
216
|
+
.where("runs.id", "=", runId)
|
|
217
|
+
.executeTakeFirst();
|
|
218
|
+
const name = row === undefined ? "" : sanitizeSenderName(row.display_name);
|
|
219
|
+
return name === "" ? undefined : name;
|
|
220
|
+
}
|
|
@@ -14,6 +14,7 @@ import { KyselyCheckpointSaver } from "./checkpointer.js";
|
|
|
14
14
|
import { ConversationLock } from "./conversation-lock.js";
|
|
15
15
|
import { ProviderRegistry } from "./providers.js";
|
|
16
16
|
import { type OrgQuota } from "./quota.js";
|
|
17
|
+
import { RunContextService } from "./run-context.service.js";
|
|
17
18
|
import { RunDrafts } from "./run-drafts.js";
|
|
18
19
|
import { RunFinish } from "./run-finish.js";
|
|
19
20
|
import type { RunJobData } from "./run-jobs.js";
|
|
@@ -63,6 +64,8 @@ export declare class RunWorker {
|
|
|
63
64
|
private readonly models;
|
|
64
65
|
/** Run start's skills catalog snapshot (reads the pinned skills' bodies, phase B). */
|
|
65
66
|
private readonly skillsCatalog;
|
|
67
|
+
/** Run start's run context (run context spec §5): who the agent is, the day, the person. */
|
|
68
|
+
private readonly runContext;
|
|
66
69
|
/**
|
|
67
70
|
* In the terminal transaction of every run: writes its open `Agent` call results
|
|
68
71
|
* (`stopOpenAgentCalls`; a no-op without dispatches); `fire` runs their observe hooks after the
|
|
@@ -96,6 +99,8 @@ export declare class RunWorker {
|
|
|
96
99
|
models: Pick<ProviderRegistry, "resolve">,
|
|
97
100
|
/** Run start's skills catalog snapshot (reads the pinned skills' bodies, phase B). */
|
|
98
101
|
skillsCatalog: Pick<SkillsCatalogService, "record">,
|
|
102
|
+
/** Run start's run context (run context spec §5): who the agent is, the day, the person. */
|
|
103
|
+
runContext: Pick<RunContextService, "record">,
|
|
99
104
|
/**
|
|
100
105
|
* In the terminal transaction of every run: writes its open `Agent` call results
|
|
101
106
|
* (`stopOpenAgentCalls`; a no-op without dispatches); `fire` runs their observe hooks after the
|