@loopingai/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/README.md +279 -0
- package/dist/a2a/agent-stub.d.ts +61 -0
- package/dist/a2a/agent-stub.d.ts.map +1 -0
- package/dist/a2a/agent-stub.js +2 -0
- package/dist/a2a/agent-stub.js.map +1 -0
- package/dist/a2a/card.d.ts +119 -0
- package/dist/a2a/card.d.ts.map +1 -0
- package/dist/a2a/card.js +115 -0
- package/dist/a2a/card.js.map +1 -0
- package/dist/a2a/context.d.ts +14 -0
- package/dist/a2a/context.d.ts.map +1 -0
- package/dist/a2a/context.js +55 -0
- package/dist/a2a/context.js.map +1 -0
- package/dist/a2a/executor.d.ts +85 -0
- package/dist/a2a/executor.d.ts.map +1 -0
- package/dist/a2a/executor.js +107 -0
- package/dist/a2a/executor.js.map +1 -0
- package/dist/a2a/index.d.ts +18 -0
- package/dist/a2a/index.d.ts.map +1 -0
- package/dist/a2a/index.js +17 -0
- package/dist/a2a/index.js.map +1 -0
- package/dist/a2a/notify.d.ts +75 -0
- package/dist/a2a/notify.d.ts.map +1 -0
- package/dist/a2a/notify.js +161 -0
- package/dist/a2a/notify.js.map +1 -0
- package/dist/a2a/parts.d.ts +46 -0
- package/dist/a2a/parts.d.ts.map +1 -0
- package/dist/a2a/parts.js +95 -0
- package/dist/a2a/parts.js.map +1 -0
- package/dist/a2a/task-store.d.ts +45 -0
- package/dist/a2a/task-store.d.ts.map +1 -0
- package/dist/a2a/task-store.js +100 -0
- package/dist/a2a/task-store.js.map +1 -0
- package/dist/a2a/task.d.ts +86 -0
- package/dist/a2a/task.d.ts.map +1 -0
- package/dist/a2a/task.js +16 -0
- package/dist/a2a/task.js.map +1 -0
- package/dist/a2a/verify.d.ts +64 -0
- package/dist/a2a/verify.d.ts.map +1 -0
- package/dist/a2a/verify.js +122 -0
- package/dist/a2a/verify.js.map +1 -0
- package/dist/agent/budget.d.ts +47 -0
- package/dist/agent/budget.d.ts.map +1 -0
- package/dist/agent/budget.js +43 -0
- package/dist/agent/budget.js.map +1 -0
- package/dist/agent/control.d.ts +110 -0
- package/dist/agent/control.d.ts.map +1 -0
- package/dist/agent/control.js +115 -0
- package/dist/agent/control.js.map +1 -0
- package/dist/agent/final-reply.d.ts +49 -0
- package/dist/agent/final-reply.d.ts.map +1 -0
- package/dist/agent/final-reply.js +52 -0
- package/dist/agent/final-reply.js.map +1 -0
- package/dist/agent/history.d.ts +83 -0
- package/dist/agent/history.d.ts.map +1 -0
- package/dist/agent/history.js +117 -0
- package/dist/agent/history.js.map +1 -0
- package/dist/agent/index.d.ts +17 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +17 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/inference.d.ts +52 -0
- package/dist/agent/inference.d.ts.map +1 -0
- package/dist/agent/inference.js +79 -0
- package/dist/agent/inference.js.map +1 -0
- package/dist/agent/model.d.ts +75 -0
- package/dist/agent/model.d.ts.map +1 -0
- package/dist/agent/model.js +62 -0
- package/dist/agent/model.js.map +1 -0
- package/dist/agent/session.d.ts +92 -0
- package/dist/agent/session.d.ts.map +1 -0
- package/dist/agent/session.js +80 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/config.d.ts +159 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +92 -0
- package/dist/config.js.map +1 -0
- package/dist/contract/index.d.ts +10 -0
- package/dist/contract/index.d.ts.map +1 -0
- package/dist/contract/index.js +9 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/contract/plugin.d.ts +163 -0
- package/dist/contract/plugin.d.ts.map +1 -0
- package/dist/contract/plugin.js +39 -0
- package/dist/contract/plugin.js.map +1 -0
- package/dist/contract/recipe.d.ts +170 -0
- package/dist/contract/recipe.d.ts.map +1 -0
- package/dist/contract/recipe.js +2 -0
- package/dist/contract/recipe.js.map +1 -0
- package/dist/contract/validation.d.ts +86 -0
- package/dist/contract/validation.d.ts.map +1 -0
- package/dist/contract/validation.js +76 -0
- package/dist/contract/validation.js.map +1 -0
- package/dist/db/db.d.ts +131 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +91 -0
- package/dist/db/db.js.map +1 -0
- package/dist/db/index.d.ts +9 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +9 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrations/index.d.ts +21 -0
- package/dist/db/migrations/index.d.ts.map +1 -0
- package/dist/db/migrations/index.js +54 -0
- package/dist/db/migrations/index.js.map +1 -0
- package/dist/db/models/subtasks.d.ts +102 -0
- package/dist/db/models/subtasks.d.ts.map +1 -0
- package/dist/db/models/subtasks.js +285 -0
- package/dist/db/models/subtasks.js.map +1 -0
- package/dist/db/models/tasks.d.ts +92 -0
- package/dist/db/models/tasks.d.ts.map +1 -0
- package/dist/db/models/tasks.js +212 -0
- package/dist/db/models/tasks.js.map +1 -0
- package/dist/db/schema.d.ts +488 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +91 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/env.d.ts +46 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +40 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/platform.d.ts +47 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +47 -0
- package/dist/platform.js.map +1 -0
- package/dist/runtime/index.d.ts +86 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +123 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/tool-families.d.ts +33 -0
- package/dist/runtime/tool-families.d.ts.map +1 -0
- package/dist/runtime/tool-families.js +62 -0
- package/dist/runtime/tool-families.js.map +1 -0
- package/dist/subagent/fingerprint.d.ts +38 -0
- package/dist/subagent/fingerprint.d.ts.map +1 -0
- package/dist/subagent/fingerprint.js +97 -0
- package/dist/subagent/fingerprint.js.map +1 -0
- package/dist/subagent/index.d.ts +147 -0
- package/dist/subagent/index.d.ts.map +1 -0
- package/dist/subagent/index.js +299 -0
- package/dist/subagent/index.js.map +1 -0
- package/dist/subagent/prompt.d.ts +34 -0
- package/dist/subagent/prompt.d.ts.map +1 -0
- package/dist/subagent/prompt.js +46 -0
- package/dist/subagent/prompt.js.map +1 -0
- package/dist/subagent/run.d.ts +151 -0
- package/dist/subagent/run.d.ts.map +1 -0
- package/dist/subagent/run.js +491 -0
- package/dist/subagent/run.js.map +1 -0
- package/dist/subagent/workspace.d.ts +65 -0
- package/dist/subagent/workspace.d.ts.map +1 -0
- package/dist/subagent/workspace.js +53 -0
- package/dist/subagent/workspace.js.map +1 -0
- package/dist/subtasks/catalog.d.ts +40 -0
- package/dist/subtasks/catalog.d.ts.map +1 -0
- package/dist/subtasks/catalog.js +36 -0
- package/dist/subtasks/catalog.js.map +1 -0
- package/dist/subtasks/decomposition.d.ts +90 -0
- package/dist/subtasks/decomposition.d.ts.map +1 -0
- package/dist/subtasks/decomposition.js +205 -0
- package/dist/subtasks/decomposition.js.map +1 -0
- package/dist/subtasks/delegate.d.ts +77 -0
- package/dist/subtasks/delegate.d.ts.map +1 -0
- package/dist/subtasks/delegate.js +102 -0
- package/dist/subtasks/delegate.js.map +1 -0
- package/dist/subtasks/index.d.ts +11 -0
- package/dist/subtasks/index.d.ts.map +1 -0
- package/dist/subtasks/index.js +11 -0
- package/dist/subtasks/index.js.map +1 -0
- package/dist/subtasks/scheduler.d.ts +49 -0
- package/dist/subtasks/scheduler.d.ts.map +1 -0
- package/dist/subtasks/scheduler.js +48 -0
- package/dist/subtasks/scheduler.js.map +1 -0
- package/dist/subtasks/subtask-types.d.ts +100 -0
- package/dist/subtasks/subtask-types.d.ts.map +1 -0
- package/dist/subtasks/subtask-types.js +111 -0
- package/dist/subtasks/subtask-types.js.map +1 -0
- package/dist/subtasks/types.d.ts +321 -0
- package/dist/subtasks/types.d.ts.map +1 -0
- package/dist/subtasks/types.js +16 -0
- package/dist/subtasks/types.js.map +1 -0
- package/dist/testing/auth.d.ts +12 -0
- package/dist/testing/auth.d.ts.map +1 -0
- package/dist/testing/auth.js +25 -0
- package/dist/testing/auth.js.map +1 -0
- package/dist/testing/do.d.ts +30 -0
- package/dist/testing/do.d.ts.map +1 -0
- package/dist/testing/do.js +26 -0
- package/dist/testing/do.js.map +1 -0
- package/dist/testing/fake-session.d.ts +27 -0
- package/dist/testing/fake-session.d.ts.map +1 -0
- package/dist/testing/fake-session.js +38 -0
- package/dist/testing/fake-session.js.map +1 -0
- package/dist/testing/fixtures.d.ts +27 -0
- package/dist/testing/fixtures.d.ts.map +1 -0
- package/dist/testing/fixtures.js +67 -0
- package/dist/testing/fixtures.js.map +1 -0
- package/dist/testing/index.d.ts +31 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +31 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/mock-model.d.ts +43 -0
- package/dist/testing/mock-model.d.ts.map +1 -0
- package/dist/testing/mock-model.js +62 -0
- package/dist/testing/mock-model.js.map +1 -0
- package/dist/testing/node.d.ts +24 -0
- package/dist/testing/node.d.ts.map +1 -0
- package/dist/testing/node.js +24 -0
- package/dist/testing/node.js.map +1 -0
- package/dist/testing/vcr-global-setup.d.ts +3 -0
- package/dist/testing/vcr-global-setup.d.ts.map +1 -0
- package/dist/testing/vcr-global-setup.js +9 -0
- package/dist/testing/vcr-global-setup.js.map +1 -0
- package/dist/testing/vcr-shared.d.ts +21 -0
- package/dist/testing/vcr-shared.d.ts.map +1 -0
- package/dist/testing/vcr-shared.js +21 -0
- package/dist/testing/vcr-shared.js.map +1 -0
- package/dist/testing/vcr-spec.d.ts +17 -0
- package/dist/testing/vcr-spec.d.ts.map +1 -0
- package/dist/testing/vcr-spec.js +72 -0
- package/dist/testing/vcr-spec.js.map +1 -0
- package/dist/testing/vcr.d.ts +81 -0
- package/dist/testing/vcr.d.ts.map +1 -0
- package/dist/testing/vcr.js +211 -0
- package/dist/testing/vcr.js.map +1 -0
- package/dist/worker/index.d.ts +62 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +194 -0
- package/dist/worker/index.js.map +1 -0
- package/eslint-rules/index.js +31 -0
- package/eslint-rules/no-deprecated-object-properties.js +81 -0
- package/package.json +147 -0
- package/scripts/generate-keys.mjs +53 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { Tool, ToolSet } from "ai";
|
|
2
|
+
import type { ReferenceCatalogEntry } from "../subtasks/catalog.js";
|
|
3
|
+
import type { SubtaskTypeRegistry } from "../subtasks/subtask-types.js";
|
|
4
|
+
import type { SubtaskDraft } from "../subtasks/types.js";
|
|
5
|
+
/**
|
|
6
|
+
* The **control tools** — the calls that end a round — and the one thing they all
|
|
7
|
+
* need that the SDK cannot do for them: checking their own input.
|
|
8
|
+
*
|
|
9
|
+
* A work tool carries an `execute`, so the SDK validates its input against the
|
|
10
|
+
* tool's schema, runs it, and feeds any failure — bad input, unknown tool, a throw
|
|
11
|
+
* from inside — back into the loop as a failed tool result. The model sees what
|
|
12
|
+
* went wrong and gets to try again, for free, for every work tool that exists or
|
|
13
|
+
* ever will.
|
|
14
|
+
*
|
|
15
|
+
* A control tool has no `execute`. The call *is* the round's output, so the loop
|
|
16
|
+
* halts on it and none of that machinery runs: **its input is never validated at
|
|
17
|
+
* all**. That is not a subtlety, it is a hole. A `final_reply` whose `text` was
|
|
18
|
+
* blank passed `nonBlank` untouched and was delivered to the user as an empty
|
|
19
|
+
* message; a `delegate` whose payload was not a decomposition at all reached
|
|
20
|
+
* {@link resolveDecomposition} and failed there on a raw `TypeError`.
|
|
21
|
+
*
|
|
22
|
+
* So each control tool declares a {@link ControlTool.parse}, and the round runs it
|
|
23
|
+
* where the SDK would have: between the call and any use of it. `parse` either
|
|
24
|
+
* produces the {@link TurnDecision} or throws, and a throw is handed straight back
|
|
25
|
+
* to the model as a failed result for that call — the same repair loop, from the
|
|
26
|
+
* same shape of feedback, that a work tool gets from the SDK. Adding a control tool
|
|
27
|
+
* means writing its `parse`; it inherits validation and repair by existing.
|
|
28
|
+
*/
|
|
29
|
+
/** What one round decided. A future `escalate` is another variant here. */
|
|
30
|
+
export type TurnDecision = {
|
|
31
|
+
kind: "reply";
|
|
32
|
+
text: string;
|
|
33
|
+
} | {
|
|
34
|
+
kind: "delegate";
|
|
35
|
+
reply: string;
|
|
36
|
+
drafts: SubtaskDraft[];
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Thrown by a {@link ControlTool.parse} for a call the round cannot use.
|
|
40
|
+
*
|
|
41
|
+
* Its `message` is written for the **model**, not for a log: it is what comes back
|
|
42
|
+
* in the failed tool result, and it is the only thing the next attempt knows about
|
|
43
|
+
* why this one was rejected. Say what was wrong with the call.
|
|
44
|
+
*/
|
|
45
|
+
export declare class ControlCallError extends Error {
|
|
46
|
+
constructor(message: string);
|
|
47
|
+
}
|
|
48
|
+
/** One control tool: what the model sees, and how the round reads what comes back. */
|
|
49
|
+
export interface ControlTool {
|
|
50
|
+
/** The tool's name, as declared to the model. */
|
|
51
|
+
readonly name: string;
|
|
52
|
+
/** The tool as the model sees it — no `execute`, by definition. */
|
|
53
|
+
readonly tool: Tool;
|
|
54
|
+
/**
|
|
55
|
+
* How this ending competes with another emitted in the same step. The highest
|
|
56
|
+
* precedence among the tools actually called wins, and the rest are dropped.
|
|
57
|
+
*
|
|
58
|
+
* It ranks by **commitment**: `delegate` starts durable work that a reply cannot
|
|
59
|
+
* undo, so a `delegate` alongside a `final_reply` means the reply is the
|
|
60
|
+
* acknowledgment *for* that work, not an answer instead of it. A future
|
|
61
|
+
* `escalate` slots in by saying how committal it is, and nothing else changes.
|
|
62
|
+
*/
|
|
63
|
+
readonly precedence: number;
|
|
64
|
+
/**
|
|
65
|
+
* Pick the one call that counts out of **every** call the attempt made to this
|
|
66
|
+
* tool, or throw a {@link ControlCallError} if a repeat is itself the error.
|
|
67
|
+
*
|
|
68
|
+
* Separate from {@link ControlTool.parse} because what a repeat means is the
|
|
69
|
+
* tool's own business — a second `delegate` would start a second batch of durable
|
|
70
|
+
* work and is refused, while a repeated `final_reply` is just the model restating
|
|
71
|
+
* its answer and the last one stands — and the round needs that answer *before* it
|
|
72
|
+
* has a decision: the call it shows back to the model in a repair has to be the
|
|
73
|
+
* same one validation rejected, not whichever happened to come first.
|
|
74
|
+
*
|
|
75
|
+
* Never called with an empty array: a tool with no calls did not end the round.
|
|
76
|
+
*/
|
|
77
|
+
select(inputs: readonly unknown[]): unknown;
|
|
78
|
+
/**
|
|
79
|
+
* Turn the selected call into the round's decision, or throw a
|
|
80
|
+
* {@link ControlCallError} describing what is wrong with it.
|
|
81
|
+
*
|
|
82
|
+
* The input is `unknown` on purpose. Nothing has checked it yet — that is this
|
|
83
|
+
* method's job, and typing it as anything else would be the assumption that
|
|
84
|
+
* caused the hole this interface exists to close.
|
|
85
|
+
*/
|
|
86
|
+
parse(input: unknown): TurnDecision;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The control tools for one round, in the order the model is shown them.
|
|
90
|
+
*
|
|
91
|
+
* Built per round rather than defined once, because validating a `delegate` needs
|
|
92
|
+
* this round's reference catalog — the same values the model was shown as
|
|
93
|
+
* `[ref N]` markers, which is what makes "reference 4" checkable at all.
|
|
94
|
+
*
|
|
95
|
+
* `delegate` is withheld from a `final` round, which has no budget left to spend on
|
|
96
|
+
* work. `final_reply` is declared on every round including that one: withhold both
|
|
97
|
+
* and the round has no legal way to end.
|
|
98
|
+
*/
|
|
99
|
+
export declare function controlTools(opts: {
|
|
100
|
+
catalog: ReferenceCatalogEntry[];
|
|
101
|
+
/** Whether this round may still hand out work (`false` on a `final` round). */
|
|
102
|
+
delegable: boolean;
|
|
103
|
+
/** The installed subtask types — what `delegate` may name. */
|
|
104
|
+
types: SubtaskTypeRegistry;
|
|
105
|
+
/** `CoreConfig.maxSubtasks`, the per-round fan-out bound. */
|
|
106
|
+
maxSubtasks: number;
|
|
107
|
+
}): ControlTool[];
|
|
108
|
+
/** The tools as the SDK takes them, in declaration order. */
|
|
109
|
+
export declare function controlToolSet(tools: ControlTool[]): ToolSet;
|
|
110
|
+
//# sourceMappingURL=control.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../../src/agent/control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAOxC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAMpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC;AAEhE;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED,sFAAsF;AACtF,MAAM,WAAW,WAAW;IAC1B,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC;IAC5C;;;;;;;OAOG;IACH,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAAC;CACrC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,+EAA+E;IAC/E,SAAS,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,KAAK,EAAE,mBAAmB,CAAC;IAC3B,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,WAAW,EAAE,CAqEhB;AAiCD,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO,CAE5D"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { FINAL_REPLY_TOOL_NAME, finalReplyInputSchema, finalReplyTool } from "./final-reply.js";
|
|
2
|
+
import { makeDecompositionProposalSchema, resolveDecomposition } from "../subtasks/decomposition.js";
|
|
3
|
+
import { DELEGATE_TOOL_NAME, makeDelegateTool } from "../subtasks/delegate.js";
|
|
4
|
+
/**
|
|
5
|
+
* Thrown by a {@link ControlTool.parse} for a call the round cannot use.
|
|
6
|
+
*
|
|
7
|
+
* Its `message` is written for the **model**, not for a log: it is what comes back
|
|
8
|
+
* in the failed tool result, and it is the only thing the next attempt knows about
|
|
9
|
+
* why this one was rejected. Say what was wrong with the call.
|
|
10
|
+
*/
|
|
11
|
+
export class ControlCallError extends Error {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = "ControlCallError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The control tools for one round, in the order the model is shown them.
|
|
19
|
+
*
|
|
20
|
+
* Built per round rather than defined once, because validating a `delegate` needs
|
|
21
|
+
* this round's reference catalog — the same values the model was shown as
|
|
22
|
+
* `[ref N]` markers, which is what makes "reference 4" checkable at all.
|
|
23
|
+
*
|
|
24
|
+
* `delegate` is withheld from a `final` round, which has no budget left to spend on
|
|
25
|
+
* work. `final_reply` is declared on every round including that one: withhold both
|
|
26
|
+
* and the round has no legal way to end.
|
|
27
|
+
*/
|
|
28
|
+
export function controlTools(opts) {
|
|
29
|
+
const tools = [
|
|
30
|
+
{
|
|
31
|
+
name: FINAL_REPLY_TOOL_NAME,
|
|
32
|
+
tool: finalReplyTool,
|
|
33
|
+
precedence: 0,
|
|
34
|
+
// The last call of a repeated set: a model that restated its answer meant
|
|
35
|
+
// the restatement.
|
|
36
|
+
select: (inputs) => inputs.at(-1),
|
|
37
|
+
parse(input) {
|
|
38
|
+
const parsed = finalReplyInputSchema.safeParse(input);
|
|
39
|
+
if (!parsed.success) {
|
|
40
|
+
throw new ControlCallError(`${FINAL_REPLY_TOOL_NAME} input is invalid — ${issues(parsed.error)}`);
|
|
41
|
+
}
|
|
42
|
+
return { kind: "reply", text: parsed.data.text.trim() };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
];
|
|
46
|
+
// A round with no registered types has nothing to delegate to, so `delegate`
|
|
47
|
+
// is withheld for the same reason a `final` round withholds it: the tool would
|
|
48
|
+
// advertise an empty enum the model has no legal way to satisfy.
|
|
49
|
+
if (opts.delegable && opts.types.keys.length > 0) {
|
|
50
|
+
const proposalSchema = makeDecompositionProposalSchema(opts.types, opts.maxSubtasks);
|
|
51
|
+
tools.push({
|
|
52
|
+
name: DELEGATE_TOOL_NAME,
|
|
53
|
+
tool: makeDelegateTool(opts.types, opts.maxSubtasks),
|
|
54
|
+
precedence: 1,
|
|
55
|
+
select(inputs) {
|
|
56
|
+
if (inputs.length > 1) {
|
|
57
|
+
throw new ControlCallError(`${DELEGATE_TOOL_NAME} was called ${inputs.length} times in one turn. ` +
|
|
58
|
+
`Delegate once, with every subtask this round needs in that single call.`);
|
|
59
|
+
}
|
|
60
|
+
return inputs[0];
|
|
61
|
+
},
|
|
62
|
+
parse(input) {
|
|
63
|
+
const parsed = proposalSchema.safeParse(input);
|
|
64
|
+
if (!parsed.success) {
|
|
65
|
+
throw new ControlCallError(`${DELEGATE_TOOL_NAME} input is invalid — ${issues(parsed.error)}`);
|
|
66
|
+
}
|
|
67
|
+
// Everything past the schema — unknown reference indexes, dependency
|
|
68
|
+
// cycles, a type's required params — throws its own error, already worded
|
|
69
|
+
// for the model.
|
|
70
|
+
const { reply, drafts } = resolveDecomposition({
|
|
71
|
+
...parsed.data,
|
|
72
|
+
subtasks: parsed.data.subtasks.map((s) => ({
|
|
73
|
+
...s,
|
|
74
|
+
params: definedParams(s.params)
|
|
75
|
+
}))
|
|
76
|
+
}, opts.catalog, opts.types);
|
|
77
|
+
return { kind: "delegate", reply, drafts };
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return tools;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Drop params the model sent as an explicit `undefined`.
|
|
85
|
+
*
|
|
86
|
+
* The delegate schema declares the union of every type's param keys, all optional,
|
|
87
|
+
* so one tool schema can serve every type (see `subtaskParamProperties`). A model
|
|
88
|
+
* that names a key and leaves it empty has sent no param, and forwarding the key
|
|
89
|
+
* with an `undefined` value would only make a missing required param report itself
|
|
90
|
+
* as a *present* one. Whether what survives satisfies the type is still
|
|
91
|
+
* `validateSubtaskParams`'s call, downstream.
|
|
92
|
+
*/
|
|
93
|
+
function definedParams(params) {
|
|
94
|
+
if (!params)
|
|
95
|
+
return undefined;
|
|
96
|
+
const entries = Object.entries(params).filter(([, v]) => v !== undefined);
|
|
97
|
+
return entries.length > 0
|
|
98
|
+
? Object.fromEntries(entries)
|
|
99
|
+
: undefined;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* A zod failure as one line the model can act on: which field, and what was wrong.
|
|
103
|
+
* The same rendering {@link file://./subtasks/subtask-types.ts validateSubtaskParams}
|
|
104
|
+
* uses, so every rejection a control call can produce reads the same way.
|
|
105
|
+
*/
|
|
106
|
+
function issues(error) {
|
|
107
|
+
return error.issues
|
|
108
|
+
.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`)
|
|
109
|
+
.join("; ");
|
|
110
|
+
}
|
|
111
|
+
/** The tools as the SDK takes them, in declaration order. */
|
|
112
|
+
export function controlToolSet(tools) {
|
|
113
|
+
return Object.fromEntries(tools.map((c) => [c.name, c.tool]));
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.js","sourceRoot":"","sources":["../../src/agent/control.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* The `final_reply` tool — the main agent answering the user itself, and the other
|
|
4
|
+
* way a round can end.
|
|
5
|
+
*
|
|
6
|
+
* A round used to end either by calling `delegate` or by stopping with plain text,
|
|
7
|
+
* and that asymmetry was the bug: to the code, "the model answered the user" and
|
|
8
|
+
* "the model narrated an action it never took" were the same outcome — a non-empty
|
|
9
|
+
* string. A model that wrote "I'll start the game" and emitted no call completed the
|
|
10
|
+
* Task successfully, having done nothing.
|
|
11
|
+
*
|
|
12
|
+
* So prose is no longer an outcome. Both endings are now named tools, the round runs
|
|
13
|
+
* with `toolChoice: "required"`, and a round that ends any other way has failed its
|
|
14
|
+
* attempt. The *choice* is still entirely the model's — the point of the design (see
|
|
15
|
+
* {@link file://./turn.ts turn.ts}) was never that the model be steered toward
|
|
16
|
+
* delegating, only that it not be forced. Picking between two named tools is also a
|
|
17
|
+
* far easier discrimination for a small model than picking between prose and a tool,
|
|
18
|
+
* which is what the weaker fallback models kept getting wrong.
|
|
19
|
+
*
|
|
20
|
+
* This lives outside `subtasks/` deliberately: replying is not a subtask concept.
|
|
21
|
+
*/
|
|
22
|
+
export declare const FINAL_REPLY_TOOL_NAME = "final_reply";
|
|
23
|
+
/**
|
|
24
|
+
* The tool as the model sees it. **Without `execute`**, exactly like
|
|
25
|
+
* {@link file://./subtasks/delegate.ts delegateTool}: the call *is* the round's
|
|
26
|
+
* output, so there is nothing for the SDK to run and the loop halts on it.
|
|
27
|
+
*
|
|
28
|
+
* Unlike `delegate`, this call is never reconstructed in a later round's history —
|
|
29
|
+
* a past reply is stored as, and replayed as, ordinary assistant text (history is
|
|
30
|
+
* text-only by design). The tool exists to constrain *generation*, not to become a
|
|
31
|
+
* new shape in the transcript.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* The call's input, exported as the zod schema rather than only as the tool's
|
|
35
|
+
* `inputSchema`, because the round has to run it itself.
|
|
36
|
+
*
|
|
37
|
+
* A tool with no `execute` never has its input validated by the SDK — the loop
|
|
38
|
+
* halts on the call and nothing checks it. That is what let a blank `text` through
|
|
39
|
+
* to the user despite {@link nonBlank}. The round now parses every control call
|
|
40
|
+
* with the tool's own schema before using it (see
|
|
41
|
+
* {@link file://./control.ts control.ts}), and needs the schema in hand to do it.
|
|
42
|
+
*/
|
|
43
|
+
export declare const finalReplyInputSchema: z.ZodObject<{
|
|
44
|
+
text: z.ZodString;
|
|
45
|
+
}, z.core.$strip>;
|
|
46
|
+
export declare const finalReplyTool: import("ai").Tool<{
|
|
47
|
+
text: string;
|
|
48
|
+
}, never, import("@ai-sdk/provider-utils").Context>;
|
|
49
|
+
//# sourceMappingURL=final-reply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"final-reply.d.ts","sourceRoot":"","sources":["../../src/agent/final-reply.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAEnD;;;;;;;;;GASG;AACH;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB;;iBAIhC,CAAC;AAEH,eAAO,MAAM,cAAc;;mDAIzB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { tool } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { nonBlank } from "../subtasks/decomposition.js";
|
|
4
|
+
/**
|
|
5
|
+
* The `final_reply` tool — the main agent answering the user itself, and the other
|
|
6
|
+
* way a round can end.
|
|
7
|
+
*
|
|
8
|
+
* A round used to end either by calling `delegate` or by stopping with plain text,
|
|
9
|
+
* and that asymmetry was the bug: to the code, "the model answered the user" and
|
|
10
|
+
* "the model narrated an action it never took" were the same outcome — a non-empty
|
|
11
|
+
* string. A model that wrote "I'll start the game" and emitted no call completed the
|
|
12
|
+
* Task successfully, having done nothing.
|
|
13
|
+
*
|
|
14
|
+
* So prose is no longer an outcome. Both endings are now named tools, the round runs
|
|
15
|
+
* with `toolChoice: "required"`, and a round that ends any other way has failed its
|
|
16
|
+
* attempt. The *choice* is still entirely the model's — the point of the design (see
|
|
17
|
+
* {@link file://./turn.ts turn.ts}) was never that the model be steered toward
|
|
18
|
+
* delegating, only that it not be forced. Picking between two named tools is also a
|
|
19
|
+
* far easier discrimination for a small model than picking between prose and a tool,
|
|
20
|
+
* which is what the weaker fallback models kept getting wrong.
|
|
21
|
+
*
|
|
22
|
+
* This lives outside `subtasks/` deliberately: replying is not a subtask concept.
|
|
23
|
+
*/
|
|
24
|
+
export const FINAL_REPLY_TOOL_NAME = "final_reply";
|
|
25
|
+
/**
|
|
26
|
+
* The tool as the model sees it. **Without `execute`**, exactly like
|
|
27
|
+
* {@link file://./subtasks/delegate.ts delegateTool}: the call *is* the round's
|
|
28
|
+
* output, so there is nothing for the SDK to run and the loop halts on it.
|
|
29
|
+
*
|
|
30
|
+
* Unlike `delegate`, this call is never reconstructed in a later round's history —
|
|
31
|
+
* a past reply is stored as, and replayed as, ordinary assistant text (history is
|
|
32
|
+
* text-only by design). The tool exists to constrain *generation*, not to become a
|
|
33
|
+
* new shape in the transcript.
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* The call's input, exported as the zod schema rather than only as the tool's
|
|
37
|
+
* `inputSchema`, because the round has to run it itself.
|
|
38
|
+
*
|
|
39
|
+
* A tool with no `execute` never has its input validated by the SDK — the loop
|
|
40
|
+
* halts on the call and nothing checks it. That is what let a blank `text` through
|
|
41
|
+
* to the user despite {@link nonBlank}. The round now parses every control call
|
|
42
|
+
* with the tool's own schema before using it (see
|
|
43
|
+
* {@link file://./control.ts control.ts}), and needs the schema in hand to do it.
|
|
44
|
+
*/
|
|
45
|
+
export const finalReplyInputSchema = z.object({
|
|
46
|
+
text: nonBlank("text").describe("Your reply, in your own voice. This is shown to the user verbatim, so it must be the complete answer and must not be blank.")
|
|
47
|
+
});
|
|
48
|
+
export const finalReplyTool = tool({
|
|
49
|
+
description: "Answer the user and end this round. Use this whenever the request is yours to answer — anything about this conversation, your own history, memory, or tools, and anything you can settle with the tools available to you here, including work that has already come back to you.",
|
|
50
|
+
inputSchema: finalReplyInputSchema
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=final-reply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"final-reply.js","sourceRoot":"","sources":["../../src/agent/final-reply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC1B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAExD;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG,aAAa,CAAC;AAEnD;;;;;;;;;GASG;AACH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,QAAQ,CAC7B,6HAA6H,CAC9H;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;IACjC,WAAW,EACT,kRAAkR;IACpR,WAAW,EAAE,qBAAqB;CACnC,CAAC,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { ModelMessage } from "ai";
|
|
2
|
+
import type { SessionMessage } from "agents/experimental/memory/session";
|
|
3
|
+
/**
|
|
4
|
+
* Session-history glue for the agent runtime: parse the gateway-authored `<turn>`
|
|
5
|
+
* provenance wrapper, and bridge between plain text and the Agents-SDK Sessions
|
|
6
|
+
* store. No A2A types cross this boundary — the {@link file://../a2a/inbound.ts
|
|
7
|
+
* A2A adapter} has already reduced the inbound message to a plain string.
|
|
8
|
+
*
|
|
9
|
+
* The gateway inlines a `<turn from="…" id="…" channel="…" at="…">…</turn>` tag
|
|
10
|
+
* into the message text in multi-actor channels so the model (and, in later
|
|
11
|
+
* phases, recall) can attribute "who said what". This agent only *parses* that
|
|
12
|
+
* wrapper — it never authors one.
|
|
13
|
+
*
|
|
14
|
+
* We persist only the user turn and the assistant's final text: intra-turn tool
|
|
15
|
+
* steps stay inside the single `generateText` call, so stored history is plain
|
|
16
|
+
* text messages and the conversion to AI-SDK `ModelMessage`s is trivial.
|
|
17
|
+
*/
|
|
18
|
+
/** The fields recovered from a gateway-rendered `<turn>` wrapper. */
|
|
19
|
+
export interface ParsedTurn {
|
|
20
|
+
from: string;
|
|
21
|
+
/** Slack user id, as rendered. */
|
|
22
|
+
id: string;
|
|
23
|
+
channel: string;
|
|
24
|
+
/** ISO-8601 instant. */
|
|
25
|
+
at: string;
|
|
26
|
+
/** The raw inner body. */
|
|
27
|
+
body: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Recover the structured provenance from a gateway-authored turn. Returns null
|
|
31
|
+
* for any text that isn't a `<turn>` wrapper (plain messages, assistant replies),
|
|
32
|
+
* so callers can treat the provenance as optional.
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseTurn(text: string): ParsedTurn | null;
|
|
35
|
+
/**
|
|
36
|
+
* Deterministic Session-message ids for the task round loop.
|
|
37
|
+
*
|
|
38
|
+
* A round runs inside a durable Workflow step that can re-run after a crash, so
|
|
39
|
+
* its Session appends must be exactly-once. `Session.appendMessage` already
|
|
40
|
+
* dedupes on message id (an id that exists is not re-written), so deriving the id
|
|
41
|
+
* from the task id + round makes the append idempotent for free — no
|
|
42
|
+
* read-then-write race, no duplicate turns in history on replay. Pair with
|
|
43
|
+
* {@link file://./session.ts appendOnce}, which reads the durable text back so a
|
|
44
|
+
* retry that re-inferred still returns the *stored* reply.
|
|
45
|
+
*
|
|
46
|
+
* These ids share the Session id-space with random UUIDs (plain turns) and the
|
|
47
|
+
* SDK's `compaction_`-prefixed summaries; the `task:` prefix cannot collide with
|
|
48
|
+
* either.
|
|
49
|
+
*/
|
|
50
|
+
/** Id of the inbound user turn for a task (appended once, by round 0). */
|
|
51
|
+
export declare function taskUserMessageId(taskId: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Id of the acknowledgment a **delegating** round publishes — the message the
|
|
54
|
+
* user sees while that round's Subtasks run. Also the anchor a later round finds
|
|
55
|
+
* to reattach the round's `delegate` call to (see
|
|
56
|
+
* {@link file://./turn.ts renderTurnMessages}), which is why it is derived from
|
|
57
|
+
* the round rather than stored.
|
|
58
|
+
*/
|
|
59
|
+
export declare function roundAckMessageId(taskId: string, round: number): string;
|
|
60
|
+
/**
|
|
61
|
+
* Recognize an acknowledgment id — **any** Task's, not just the one being
|
|
62
|
+
* rendered. A Session outlives the Task that wrote it and is shared by every Task
|
|
63
|
+
* from the same caller, so its history accumulates acks the current render has no
|
|
64
|
+
* branches for: earlier Tasks' acks, and (in the window between a round's ack
|
|
65
|
+
* append and its Subtask rows) this Task's own. Both are the agent's scaffolding
|
|
66
|
+
* rather than conversation, so both must stay out of the reference catalog; the
|
|
67
|
+
* `branches`-derived anchor map alone cannot see either.
|
|
68
|
+
*
|
|
69
|
+
* Returns the parsed Task id and round so the caller can tell whose ack it is.
|
|
70
|
+
*/
|
|
71
|
+
export declare function parseRoundAckMessageId(id: string): {
|
|
72
|
+
taskId: string;
|
|
73
|
+
round: number;
|
|
74
|
+
} | null;
|
|
75
|
+
/** Id of the terminal reply — the round in which the agent answered the user. */
|
|
76
|
+
export declare function finalReplyMessageId(taskId: string): string;
|
|
77
|
+
/** A Sessions-store message with a caller-chosen (deterministic) id. */
|
|
78
|
+
export declare function deterministicSessionMessage(id: string, role: "user" | "assistant", text: string): SessionMessage;
|
|
79
|
+
/** Concatenate the text parts of a stored session message. */
|
|
80
|
+
export declare function sessionText(m: SessionMessage): string;
|
|
81
|
+
/** Convert stored history to AI-SDK model messages (user/assistant text only). */
|
|
82
|
+
export declare function toModelMessages(history: SessionMessage[]): ModelMessage[];
|
|
83
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/agent/history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE;;;;;;;;;;;;;;GAcG;AAEH,qEAAqE;AACrE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAyBD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAYzD;AAED;;;;;;;;;;;;;;GAcG;AAEH,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvE;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,MAAM,GACT;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAG1C;AAED,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wEAAwE;AACxE,wBAAgB,2BAA2B,CACzC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,GAAG,WAAW,EAC1B,IAAI,EAAE,MAAM,GACX,cAAc,CAOhB;AAED,8DAA8D;AAC9D,wBAAgB,WAAW,CAAC,CAAC,EAAE,cAAc,GAAG,MAAM,CAKrD;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,YAAY,EAAE,CAOzE"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const TURN_TAG_RE = /^<turn\b([^>]*)>([\s\S]*)<\/turn>$/;
|
|
2
|
+
const ATTR_RE = /(\w+)="([^"]*)"/g;
|
|
3
|
+
function parseAttrs(raw) {
|
|
4
|
+
const out = {};
|
|
5
|
+
let m;
|
|
6
|
+
ATTR_RE.lastIndex = 0;
|
|
7
|
+
while ((m = ATTR_RE.exec(raw)) !== null)
|
|
8
|
+
out[m[1]] = m[2];
|
|
9
|
+
return out;
|
|
10
|
+
}
|
|
11
|
+
const ATTR_UNESCAPES = {
|
|
12
|
+
amp: "&",
|
|
13
|
+
lt: "<",
|
|
14
|
+
gt: ">",
|
|
15
|
+
quot: '"'
|
|
16
|
+
};
|
|
17
|
+
/** Reverse the gateway's attribute escaping — single pass so `&` round-trips. */
|
|
18
|
+
function unescAttr(value) {
|
|
19
|
+
return value.replace(/&(amp|lt|gt|quot);/g, (_, e) => ATTR_UNESCAPES[e]);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Recover the structured provenance from a gateway-authored turn. Returns null
|
|
23
|
+
* for any text that isn't a `<turn>` wrapper (plain messages, assistant replies),
|
|
24
|
+
* so callers can treat the provenance as optional.
|
|
25
|
+
*/
|
|
26
|
+
export function parseTurn(text) {
|
|
27
|
+
const m = TURN_TAG_RE.exec(text);
|
|
28
|
+
if (!m)
|
|
29
|
+
return null;
|
|
30
|
+
const attrs = parseAttrs(m[1]);
|
|
31
|
+
if (!attrs.from || !attrs.id || !attrs.channel || !attrs.at)
|
|
32
|
+
return null;
|
|
33
|
+
return {
|
|
34
|
+
from: unescAttr(attrs.from),
|
|
35
|
+
id: unescAttr(attrs.id),
|
|
36
|
+
channel: unescAttr(attrs.channel),
|
|
37
|
+
at: unescAttr(attrs.at),
|
|
38
|
+
body: m[2]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Deterministic Session-message ids for the task round loop.
|
|
43
|
+
*
|
|
44
|
+
* A round runs inside a durable Workflow step that can re-run after a crash, so
|
|
45
|
+
* its Session appends must be exactly-once. `Session.appendMessage` already
|
|
46
|
+
* dedupes on message id (an id that exists is not re-written), so deriving the id
|
|
47
|
+
* from the task id + round makes the append idempotent for free — no
|
|
48
|
+
* read-then-write race, no duplicate turns in history on replay. Pair with
|
|
49
|
+
* {@link file://./session.ts appendOnce}, which reads the durable text back so a
|
|
50
|
+
* retry that re-inferred still returns the *stored* reply.
|
|
51
|
+
*
|
|
52
|
+
* These ids share the Session id-space with random UUIDs (plain turns) and the
|
|
53
|
+
* SDK's `compaction_`-prefixed summaries; the `task:` prefix cannot collide with
|
|
54
|
+
* either.
|
|
55
|
+
*/
|
|
56
|
+
/** Id of the inbound user turn for a task (appended once, by round 0). */
|
|
57
|
+
export function taskUserMessageId(taskId) {
|
|
58
|
+
return `task:${taskId}:user`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Id of the acknowledgment a **delegating** round publishes — the message the
|
|
62
|
+
* user sees while that round's Subtasks run. Also the anchor a later round finds
|
|
63
|
+
* to reattach the round's `delegate` call to (see
|
|
64
|
+
* {@link file://./turn.ts renderTurnMessages}), which is why it is derived from
|
|
65
|
+
* the round rather than stored.
|
|
66
|
+
*/
|
|
67
|
+
export function roundAckMessageId(taskId, round) {
|
|
68
|
+
return `task:${taskId}:round:${round}:ack`;
|
|
69
|
+
}
|
|
70
|
+
/** Matches {@link roundAckMessageId}; the trailing suffix is fixed, so the greedy
|
|
71
|
+
* task-id group cannot swallow it. */
|
|
72
|
+
const ROUND_ACK_ID = /^task:(.+):round:(\d+):ack$/;
|
|
73
|
+
/**
|
|
74
|
+
* Recognize an acknowledgment id — **any** Task's, not just the one being
|
|
75
|
+
* rendered. A Session outlives the Task that wrote it and is shared by every Task
|
|
76
|
+
* from the same caller, so its history accumulates acks the current render has no
|
|
77
|
+
* branches for: earlier Tasks' acks, and (in the window between a round's ack
|
|
78
|
+
* append and its Subtask rows) this Task's own. Both are the agent's scaffolding
|
|
79
|
+
* rather than conversation, so both must stay out of the reference catalog; the
|
|
80
|
+
* `branches`-derived anchor map alone cannot see either.
|
|
81
|
+
*
|
|
82
|
+
* Returns the parsed Task id and round so the caller can tell whose ack it is.
|
|
83
|
+
*/
|
|
84
|
+
export function parseRoundAckMessageId(id) {
|
|
85
|
+
const match = ROUND_ACK_ID.exec(id);
|
|
86
|
+
return match ? { taskId: match[1], round: Number(match[2]) } : null;
|
|
87
|
+
}
|
|
88
|
+
/** Id of the terminal reply — the round in which the agent answered the user. */
|
|
89
|
+
export function finalReplyMessageId(taskId) {
|
|
90
|
+
return `task:${taskId}:reply:final`;
|
|
91
|
+
}
|
|
92
|
+
/** A Sessions-store message with a caller-chosen (deterministic) id. */
|
|
93
|
+
export function deterministicSessionMessage(id, role, text) {
|
|
94
|
+
return {
|
|
95
|
+
id,
|
|
96
|
+
role,
|
|
97
|
+
createdAt: new Date(),
|
|
98
|
+
parts: [{ type: "text", text }]
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Concatenate the text parts of a stored session message. */
|
|
102
|
+
export function sessionText(m) {
|
|
103
|
+
return m.parts
|
|
104
|
+
.filter((p) => p.type === "text" && typeof p.text === "string")
|
|
105
|
+
.map((p) => p.text)
|
|
106
|
+
.join("");
|
|
107
|
+
}
|
|
108
|
+
/** Convert stored history to AI-SDK model messages (user/assistant text only). */
|
|
109
|
+
export function toModelMessages(history) {
|
|
110
|
+
return history
|
|
111
|
+
.filter((m) => m.role === "user" || m.role === "assistant")
|
|
112
|
+
.map((m) => ({
|
|
113
|
+
role: m.role,
|
|
114
|
+
content: sessionText(m)
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/agent/history.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@loopingai/core/agent` — the primitives a loop is built from.
|
|
3
|
+
*
|
|
4
|
+
* Core ships no loop. `turn.ts` / `loop.ts` are the agent's, because how a round
|
|
5
|
+
* ends is the one thing every agent genuinely differs on. What core owns is
|
|
6
|
+
* everything both predecessor loops needed identically: the session, the model
|
|
7
|
+
* pair with its fallback, the budget, and the control-tool abstraction that
|
|
8
|
+
* turns "the model called something that ends the round" into a checked value.
|
|
9
|
+
*/
|
|
10
|
+
export { newTurnBudget, stepAllowance, type TurnBudget } from "./budget.js";
|
|
11
|
+
export { createModelRuntime, type Embed, type GatewayMetadata, type ModelOverrides, type ModelPair, type ModelRuntime, type ModelRuntimeDeps } from "./model.js";
|
|
12
|
+
export { appendOnce, archivingCompaction, buildAgentSession, type AgentSessionOptions, type SessionHost, type SessionLike } from "./session.js";
|
|
13
|
+
export { deterministicSessionMessage, finalReplyMessageId, parseRoundAckMessageId, parseTurn, roundAckMessageId, sessionText, taskUserMessageId, toModelMessages, type ParsedTurn } from "./history.js";
|
|
14
|
+
export { buildIntermediateContentHandler, isTransientAiError, type OnContent } from "./inference.js";
|
|
15
|
+
export { ControlCallError, controlTools, controlToolSet, type ControlTool, type TurnDecision } from "./control.js";
|
|
16
|
+
export { FINAL_REPLY_TOOL_NAME, finalReplyInputSchema, finalReplyTool } from "./final-reply.js";
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,EACL,kBAAkB,EAClB,KAAK,KAAK,EACV,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,sBAAsB,EACtB,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,+BAA+B,EAC/B,kBAAkB,EAClB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACf,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@loopingai/core/agent` — the primitives a loop is built from.
|
|
3
|
+
*
|
|
4
|
+
* Core ships no loop. `turn.ts` / `loop.ts` are the agent's, because how a round
|
|
5
|
+
* ends is the one thing every agent genuinely differs on. What core owns is
|
|
6
|
+
* everything both predecessor loops needed identically: the session, the model
|
|
7
|
+
* pair with its fallback, the budget, and the control-tool abstraction that
|
|
8
|
+
* turns "the model called something that ends the round" into a checked value.
|
|
9
|
+
*/
|
|
10
|
+
export { newTurnBudget, stepAllowance } from "./budget.js";
|
|
11
|
+
export { createModelRuntime } from "./model.js";
|
|
12
|
+
export { appendOnce, archivingCompaction, buildAgentSession } from "./session.js";
|
|
13
|
+
export { deterministicSessionMessage, finalReplyMessageId, parseRoundAckMessageId, parseTurn, roundAckMessageId, sessionText, taskUserMessageId, toModelMessages } from "./history.js";
|
|
14
|
+
export { buildIntermediateContentHandler, isTransientAiError } from "./inference.js";
|
|
15
|
+
export { ControlCallError, controlTools, controlToolSet } from "./control.js";
|
|
16
|
+
export { FINAL_REPLY_TOOL_NAME, finalReplyInputSchema, finalReplyTool } from "./final-reply.js";
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAmB,MAAM,aAAa,CAAC;AAE5E,OAAO,EACL,kBAAkB,EAOnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,iBAAiB,EAIlB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,sBAAsB,EACtB,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,eAAe,EAEhB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,+BAA+B,EAC/B,kBAAkB,EAEnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,EAGf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACf,MAAM,kBAAkB,CAAC"}
|