deepclause-sdk 0.2.2 → 0.3.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/README.md +72 -3
- package/dist/agent.d.ts +17 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +148 -42
- package/dist/agent.js.map +1 -1
- package/dist/cli/config.d.ts +12 -12
- package/dist/cli/repl.d.ts +13 -1
- package/dist/cli/repl.d.ts.map +1 -1
- package/dist/cli/repl.js +145 -4
- package/dist/cli/repl.js.map +1 -1
- package/dist/forms/index.d.ts +3 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/index.js +3 -0
- package/dist/forms/index.js.map +1 -0
- package/dist/forms/registry.d.ts +119 -0
- package/dist/forms/registry.d.ts.map +1 -0
- package/dist/forms/registry.js +256 -0
- package/dist/forms/registry.js.map +1 -0
- package/dist/forms/spec.d.ts +193 -0
- package/dist/forms/spec.d.ts.map +1 -0
- package/dist/forms/spec.js +295 -0
- package/dist/forms/spec.js.map +1 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/prolog/loader.d.ts +18 -0
- package/dist/prolog/loader.d.ts.map +1 -1
- package/dist/prolog/loader.js +26 -1
- package/dist/prolog/loader.js.map +1 -1
- package/dist/prolog-src/deepclause_mi.pl +619 -28
- package/dist/repl/agent.d.ts +4 -0
- package/dist/repl/agent.d.ts.map +1 -1
- package/dist/repl/agent.js +2 -0
- package/dist/repl/agent.js.map +1 -1
- package/dist/repl/form-widget.d.ts +56 -0
- package/dist/repl/form-widget.d.ts.map +1 -0
- package/dist/repl/form-widget.js +289 -0
- package/dist/repl/form-widget.js.map +1 -0
- package/dist/repl/harness-tools.d.ts +3 -1
- package/dist/repl/harness-tools.d.ts.map +1 -1
- package/dist/repl/harness-tools.js +13 -56
- package/dist/repl/harness-tools.js.map +1 -1
- package/dist/repl/history.d.ts +2 -1
- package/dist/repl/history.d.ts.map +1 -1
- package/dist/repl/history.js +34 -8
- package/dist/repl/history.js.map +1 -1
- package/dist/repl/index.d.ts +14 -2
- package/dist/repl/index.d.ts.map +1 -1
- package/dist/repl/index.js +6 -0
- package/dist/repl/index.js.map +1 -1
- package/dist/repl/process-backend.d.ts +2 -2
- package/dist/repl/process-backend.d.ts.map +1 -1
- package/dist/repl/process-executor.d.ts +11 -2
- package/dist/repl/process-executor.d.ts.map +1 -1
- package/dist/repl/process-executor.js +67 -18
- package/dist/repl/process-executor.js.map +1 -1
- package/dist/repl/process-worker.d.ts +35 -4
- package/dist/repl/process-worker.d.ts.map +1 -1
- package/dist/repl/process-worker.js +78 -38
- package/dist/repl/process-worker.js.map +1 -1
- package/dist/repl/processes.d.ts +4 -0
- package/dist/repl/processes.d.ts.map +1 -1
- package/dist/repl/processes.js +20 -0
- package/dist/repl/processes.js.map +1 -1
- package/dist/repl/render.d.ts +17 -0
- package/dist/repl/render.d.ts.map +1 -1
- package/dist/repl/render.js +50 -0
- package/dist/repl/render.js.map +1 -1
- package/dist/repl/session.d.ts +105 -7
- package/dist/repl/session.d.ts.map +1 -1
- package/dist/repl/session.js +219 -15
- package/dist/repl/session.js.map +1 -1
- package/dist/repl/tui/form-view.d.ts +17 -0
- package/dist/repl/tui/form-view.d.ts.map +1 -0
- package/dist/repl/tui/form-view.js +25 -0
- package/dist/repl/tui/form-view.js.map +1 -0
- package/dist/repl/tui/renderer.d.ts +4 -0
- package/dist/repl/tui/renderer.d.ts.map +1 -1
- package/dist/repl/tui/renderer.js +12 -0
- package/dist/repl/tui/renderer.js.map +1 -1
- package/dist/repl/worker-host.d.ts +16 -2
- package/dist/repl/worker-host.d.ts.map +1 -1
- package/dist/repl/worker-host.js +38 -6
- package/dist/repl/worker-host.js.map +1 -1
- package/dist/repl/worker-protocol.d.ts +14 -0
- package/dist/repl/worker-protocol.d.ts.map +1 -1
- package/dist/repl/worker-protocol.js +8 -1
- package/dist/repl/worker-protocol.js.map +1 -1
- package/dist/runner.d.ts +63 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +350 -40
- package/dist/runner.js.map +1 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +12 -0
- package/dist/sdk.js.map +1 -1
- package/dist/system/assets/docs/AGENT_PROMPT.md +387 -18
- package/dist/system/assets/docs/CHAT_PROMPT.md +28 -0
- package/dist/system/assets/docs/DML_AUTHORING.md +1 -1
- package/dist/system/assets/docs/DML_FORMS.md +740 -0
- package/dist/system/assets/docs/DML_REFERENCE.md +180 -4
- package/dist/system/assets/docs/HARNESS_EXAMPLES.md +94 -0
- package/dist/system/assets/index.d.ts +2 -2
- package/dist/system/assets/index.d.ts.map +1 -1
- package/dist/system/assets/index.js +4 -0
- package/dist/system/assets/index.js.map +1 -1
- package/dist/system/environment.d.ts +6 -0
- package/dist/system/environment.d.ts.map +1 -1
- package/dist/system/environment.js +5 -4
- package/dist/system/environment.js.map +1 -1
- package/dist/types.d.ts +35 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -2
- package/src/prolog-src/deepclause_mi.pl +619 -28
package/README.md
CHANGED
|
@@ -411,9 +411,10 @@ dml> /ps --watch --logs
|
|
|
411
411
|
debater › finished
|
|
412
412
|
```
|
|
413
413
|
|
|
414
|
-
The authoring agent uses the same machinery through its `
|
|
415
|
-
|
|
416
|
-
|
|
414
|
+
The authoring agent uses the same machinery through its `ps` / `send` / `stop` /
|
|
415
|
+
`swarm` / `wait` tools, and drives `spawn` and request/reply through `execute`
|
|
416
|
+
with the DML built-ins (`spawn`, `send`/`receive`, `serve`/`service_call`,
|
|
417
|
+
`swarm`/`pmap`). A
|
|
417
418
|
subagent runs against a **private snapshot** of the module with **value
|
|
418
419
|
semantics** — a result comes back by message, never by a shared variable — which
|
|
419
420
|
is what makes it safe to run many at once.
|
|
@@ -461,6 +462,66 @@ only for models that support it.
|
|
|
461
462
|
Credentials live in pi's agent dir (`~/.pi/agent`) unless `backend.agentDir`
|
|
462
463
|
overrides it. Existing pi installations stay untouched.
|
|
463
464
|
|
|
465
|
+
### Local models (Ollama, llama.cpp, vLLM)
|
|
466
|
+
|
|
467
|
+
The default `pi` backend reads pi's `models.json`, which can declare **custom
|
|
468
|
+
OpenAI-compatible providers**, so a local server needs no SDK changes:
|
|
469
|
+
|
|
470
|
+
```jsonc
|
|
471
|
+
// ~/.pi/agent/models.json
|
|
472
|
+
{
|
|
473
|
+
"providers": {
|
|
474
|
+
"loc": {
|
|
475
|
+
"name": "Local server",
|
|
476
|
+
"baseUrl": "http://localhost:11434/v1", // Ollama; llama.cpp: http://127.0.0.1:8080/v1
|
|
477
|
+
"apiKey": "ollama", // any string; satisfies the auth check
|
|
478
|
+
"api": "openai-completions", // not openai-responses
|
|
479
|
+
"models": [{
|
|
480
|
+
"id": "llama3.1",
|
|
481
|
+
"contextWindow": 131072,
|
|
482
|
+
"maxTokens": 8192,
|
|
483
|
+
"reasoning": false,
|
|
484
|
+
"input": ["text"],
|
|
485
|
+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
486
|
+
}]
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
```bash
|
|
493
|
+
deepclause set-backend pi --list # lists "loc (Local server) — configured [api-key]"
|
|
494
|
+
# and the model "loc/lecho"
|
|
495
|
+
deepclause repl --model loc:llama3.1
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
`run` has no `--model` flag; set `backend.model` instead. DML can route a single
|
|
499
|
+
step there as well — `with_model("loc:llama3.1", Goal)`.
|
|
500
|
+
|
|
501
|
+
Point at a non-default file with `backend.modelsPath` in
|
|
502
|
+
`.deepclause/config.json` (or `PI_CODING_AGENT_DIR` to move pi's whole agent
|
|
503
|
+
dir), which keeps a project's catalog in the repository rather than the home
|
|
504
|
+
directory:
|
|
505
|
+
|
|
506
|
+
```json
|
|
507
|
+
{ "backend": { "kind": "pi", "model": "loc:llama3.1", "modelsPath": "./agent/models.json" } }
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
- **`api` picks the wire protocol.** `openai-completions` is what Ollama,
|
|
511
|
+
llama.cpp, vLLM and SGLang serve; `openai-responses` is the newer OpenAI API.
|
|
512
|
+
Per-provider `compat` flags cover servers that differ
|
|
513
|
+
(`maxTokensField`, `supportsUsageInStreaming`, `requiresToolResultName`, …),
|
|
514
|
+
and a model's `samplingParams` forwards `top_p`/`top_k`/`repetition_penalty`.
|
|
515
|
+
- **Tool calling is required for `task/N`**, which ends by calling
|
|
516
|
+
`set_result`/`finish`; a text-only model exhausts the turn instead. `chat/1`
|
|
517
|
+
needs no tools, so a small local model is usable there, or pick a model whose
|
|
518
|
+
chat template supports tools.
|
|
519
|
+
- **`list-models` prints the bundled model database** and will not show custom
|
|
520
|
+
entries; `set-backend pi --list` prints pi's catalog, which does.
|
|
521
|
+
- The `env` backend can also point at a local server
|
|
522
|
+
(`providers.openai.baseUrl` + `apiKey`), but it always speaks chat completions
|
|
523
|
+
and **`repl` ignores `providers.*.baseUrl`** today — prefer the `pi` backend.
|
|
524
|
+
|
|
464
525
|
## run
|
|
465
526
|
|
|
466
527
|
`run` uses the **same engine as the REPL**: it opens a module, loads the
|
|
@@ -662,6 +723,13 @@ npm test # vitest
|
|
|
662
723
|
npm run repl # deepclause repl via tsx
|
|
663
724
|
```
|
|
664
725
|
|
|
726
|
+
**`npm run build` is required for the default process backend.** L2 (worker)
|
|
727
|
+
processes run `dist/repl/process-worker.js`, so editing `src` without rebuilding
|
|
728
|
+
runs old worker code against a new main — the symptom used to be child sessions
|
|
729
|
+
that silently had no harness. `WORKER_PROTOCOL_VERSION` now fails that loudly
|
|
730
|
+
(`stale L2 process worker: … run 'npm run build'`). The tests that need it
|
|
731
|
+
(`repl-process-worker-child`) skip themselves when `dist` is absent.
|
|
732
|
+
|
|
665
733
|
See [`docs/`](docs/): [`SUBAGENTS.md`](docs/SUBAGENTS.md) (subagents and
|
|
666
734
|
concurrency), [`STATUS.md`](docs/STATUS.md) (current state),
|
|
667
735
|
[`REPL.md`](docs/REPL.md),
|
|
@@ -670,6 +738,7 @@ concurrency), [`STATUS.md`](docs/STATUS.md) (current state),
|
|
|
670
738
|
[`DML_MEDIA.md`](docs/DML_MEDIA.md),
|
|
671
739
|
[`DML_MODEL_SWITCHING.md`](docs/DML_MODEL_SWITCHING.md),
|
|
672
740
|
[`DML_REPL_WORKER_EXECUTION.md`](docs/DML_REPL_WORKER_EXECUTION.md) (plan),
|
|
741
|
+
[`DML_FORMS.md`](docs/DML_FORMS.md) (structured human input),
|
|
673
742
|
[`JUDGMENT_BACKENDS.md`](docs/JUDGMENT_BACKENDS.md).
|
|
674
743
|
|
|
675
744
|
## License
|
package/dist/agent.d.ts
CHANGED
|
@@ -11,6 +11,21 @@ import type { ExecutionEnvironment } from './system/runtime/shell-manager.js';
|
|
|
11
11
|
export interface AgentLoopOptions {
|
|
12
12
|
taskDescription: string;
|
|
13
13
|
outputVars: (string | TypedVar)[];
|
|
14
|
+
/**
|
|
15
|
+
* Conversational mode: a chat turn, not a task.
|
|
16
|
+
*
|
|
17
|
+
* A traditional agent loop — tools, but no `finish`/`set_result`, and the turn
|
|
18
|
+
* ends when the model stops calling tools. That is how a chat agent works: it
|
|
19
|
+
* replies, and the next message starts the next turn. Task mode, by contrast,
|
|
20
|
+
* insists on an explicit `finish` and nudges the model when it does not.
|
|
21
|
+
*/
|
|
22
|
+
conversational?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* A conversational turn has run out of tool calls. Return a message to keep the
|
|
25
|
+
* turn alive (the runner uses it to deliver a form the person is still filling
|
|
26
|
+
* in), or null to end the turn.
|
|
27
|
+
*/
|
|
28
|
+
onIdleTurn?: () => Promise<string | null>;
|
|
14
29
|
memory: MemoryMessage[];
|
|
15
30
|
tools: Map<string, ToolDefinition>;
|
|
16
31
|
/**
|
|
@@ -25,6 +40,8 @@ export interface AgentLoopOptions {
|
|
|
25
40
|
* and dates in the dark.
|
|
26
41
|
*/
|
|
27
42
|
environment?: ExecutionEnvironment;
|
|
43
|
+
/** Name of the single capability host tool (default `bash`; the browser uses `python`). */
|
|
44
|
+
capabilityTool?: string;
|
|
28
45
|
modelOptions: {
|
|
29
46
|
model: string;
|
|
30
47
|
provider: string;
|
package/dist/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
|
package/dist/agent.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - Uses Zod schemas for tool definitions
|
|
7
7
|
* - Uses result.response.messages for message history management
|
|
8
8
|
*/
|
|
9
|
-
import { generateText, streamText, hasToolCall, tool as aiTool } from 'ai';
|
|
9
|
+
import { generateText, streamText, hasToolCall, stepCountIs, tool as aiTool } from 'ai';
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import { createModelProvider } from './prolog/bridge.js';
|
|
12
12
|
import { readSystemPromptAsset } from './system/assets/index.js';
|
|
@@ -512,7 +512,9 @@ async function runInjectedAgentLoop(options, normalizedOutputVars, combinedSyste
|
|
|
512
512
|
success: false,
|
|
513
513
|
};
|
|
514
514
|
const requiredVarNames = normalizedOutputVars.map((variable) => variable.name);
|
|
515
|
-
|
|
515
|
+
// A chat turn has no `finish`/`set_result`: it ends when the model stops calling
|
|
516
|
+
// tools, like a traditional agent loop.
|
|
517
|
+
const backendTools = options.conversational ? [] : [{
|
|
516
518
|
name: 'finish',
|
|
517
519
|
description: 'Complete the task. success=true requires every requested result variable to be set.',
|
|
518
520
|
parameters: {
|
|
@@ -575,7 +577,7 @@ async function runInjectedAgentLoop(options, normalizedOutputVars, combinedSyste
|
|
|
575
577
|
const messages = [
|
|
576
578
|
{ role: 'system', content: combinedSystemPrompt },
|
|
577
579
|
...historyMessages,
|
|
578
|
-
{ role: 'user', content: `Subtask: ${options.taskDescription}` },
|
|
580
|
+
{ role: 'user', content: options.conversational ? options.taskDescription : `Subtask: ${options.taskDescription}` },
|
|
579
581
|
];
|
|
580
582
|
const maxIterations = Math.max(1, Number(process.env.DC_MAX_ITERATIONS) || 1000);
|
|
581
583
|
for (let iteration = 0; iteration < maxIterations && !state.finished; iteration++) {
|
|
@@ -707,10 +709,24 @@ async function runInjectedAgentLoop(options, normalizedOutputVars, combinedSyste
|
|
|
707
709
|
});
|
|
708
710
|
}
|
|
709
711
|
if (toolCalls.length === 0 && !state.finished) {
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
712
|
+
if (options.conversational) {
|
|
713
|
+
// The reply is the answer — unless the host is still holding something
|
|
714
|
+
// for this turn (a form the person has not submitted yet).
|
|
715
|
+
const injected = options.onIdleTurn ? await options.onIdleTurn() : null;
|
|
716
|
+
if (injected) {
|
|
717
|
+
messages.push({ role: 'user', content: injected });
|
|
718
|
+
}
|
|
719
|
+
else {
|
|
720
|
+
state.finished = true;
|
|
721
|
+
state.success = true;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
else {
|
|
725
|
+
messages.push({
|
|
726
|
+
role: 'user',
|
|
727
|
+
content: 'Continue the task. Use set_result for each requested output, then call finish.',
|
|
728
|
+
});
|
|
729
|
+
}
|
|
714
730
|
}
|
|
715
731
|
}
|
|
716
732
|
return {
|
|
@@ -748,26 +764,28 @@ export async function runAgentLoop(options) {
|
|
|
748
764
|
// Build the AI SDK tools using Zod schemas
|
|
749
765
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
750
766
|
const aiTools = {};
|
|
751
|
-
// Add finish tool with Zod schema
|
|
767
|
+
// Add finish tool with Zod schema. A chat turn has no finish: the model replies
|
|
768
|
+
// and stops, and the next message starts the next turn.
|
|
752
769
|
const requiredVarNames = normalizedOutputVars.map(v => v.name);
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
770
|
+
if (!options.conversational)
|
|
771
|
+
aiTools['finish'] = aiTool({
|
|
772
|
+
description: 'CRITICAL: You MUST call this tool to complete the task and return success/failure. Call with success=true if you have set all required results, or success=false if the task is impossible.',
|
|
773
|
+
inputSchema: z.object({
|
|
774
|
+
success: z.boolean().describe('Whether the task was completed successfully')
|
|
775
|
+
}),
|
|
776
|
+
execute: async ({ success: s }) => {
|
|
777
|
+
// Guard: success=true requires all output variables to be set
|
|
778
|
+
if (s && requiredVarNames.length > 0) {
|
|
779
|
+
const missing = requiredVarNames.filter(v => !(v in variables));
|
|
780
|
+
if (missing.length > 0) {
|
|
781
|
+
return { finished: false, error: `Cannot finish with success=true — missing required result variable(s): ${missing.join(', ')}. Call set_result for each before finishing.` };
|
|
782
|
+
}
|
|
764
783
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
}
|
|
770
|
-
});
|
|
784
|
+
finished = true;
|
|
785
|
+
success = s;
|
|
786
|
+
return { finished: true, success: s };
|
|
787
|
+
},
|
|
788
|
+
});
|
|
771
789
|
// Add set_result tool for output variables
|
|
772
790
|
if (normalizedOutputVars.length > 0) {
|
|
773
791
|
const varNames = normalizedOutputVars.map(v => v.name);
|
|
@@ -850,6 +868,8 @@ export async function runAgentLoop(options) {
|
|
|
850
868
|
tools,
|
|
851
869
|
workspacePath: options.workspacePath,
|
|
852
870
|
environment: options.environment,
|
|
871
|
+
capabilityTool: options.capabilityTool,
|
|
872
|
+
conversational: options.conversational,
|
|
853
873
|
});
|
|
854
874
|
// Extract system context from memory (user-defined system() calls)
|
|
855
875
|
const systemContext = memory
|
|
@@ -949,7 +969,7 @@ export async function runAgentLoop(options) {
|
|
|
949
969
|
maxOutputTokens: modelOptions.maxOutputTokens,
|
|
950
970
|
abortSignal: signal,
|
|
951
971
|
providerOptions: modelOptions.providerOptions,
|
|
952
|
-
stopWhen: hasToolCall('finish'),
|
|
972
|
+
stopWhen: options.conversational ? stepCountIs(1) : hasToolCall('finish'),
|
|
953
973
|
onStepFinish: (step) => {
|
|
954
974
|
debugLog(`Step finished: finishReason=${step.finishReason} toolCalls=${step.toolCalls?.length ?? 0}`);
|
|
955
975
|
},
|
|
@@ -1122,10 +1142,28 @@ export async function runAgentLoop(options) {
|
|
|
1122
1142
|
outputs.push('Agent loop detected repeated non-progressing responses and stopped early.');
|
|
1123
1143
|
break;
|
|
1124
1144
|
}
|
|
1145
|
+
// A chat turn ends when the model stops calling tools: that reply is the
|
|
1146
|
+
// answer, and the next message starts the next turn. Unless the host is
|
|
1147
|
+
// still holding something for this turn — a form the person has not
|
|
1148
|
+
// submitted yet — in which case its submission is injected and the loop
|
|
1149
|
+
// continues, so the turn never ends with an unanswered form.
|
|
1150
|
+
if (options.conversational && !finished && toolCallsThisIteration.length === 0) {
|
|
1151
|
+
const injected = options.onIdleTurn ? await options.onIdleTurn() : null;
|
|
1152
|
+
if (injected) {
|
|
1153
|
+
messages.push({ role: 'user', content: injected });
|
|
1154
|
+
}
|
|
1155
|
+
else {
|
|
1156
|
+
finished = true;
|
|
1157
|
+
success = true;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1125
1160
|
// If no tool calls were made, nudge the model to act.
|
|
1126
1161
|
// This handles 'stop', 'other', and any unexpected finish reason.
|
|
1127
|
-
|
|
1128
|
-
const
|
|
1162
|
+
// A chat turn is never nudged: the model simply finished its reply.
|
|
1163
|
+
const recoveryPrompt = options.conversational
|
|
1164
|
+
? null
|
|
1165
|
+
: buildRecoveryPrompt(normalizedOutputVars, repeatedStallCount, toolCallsThisIteration.length === 0);
|
|
1166
|
+
const continuationPrompt = !options.conversational && !finished && getLastMessageRole(messages) === 'assistant'
|
|
1129
1167
|
? buildAssistantContinuationPrompt(normalizedOutputVars)
|
|
1130
1168
|
: null;
|
|
1131
1169
|
const nextPrompt = recoveryPrompt ?? continuationPrompt;
|
|
@@ -1242,10 +1280,28 @@ export async function runAgentLoop(options) {
|
|
|
1242
1280
|
outputs.push('Agent loop detected repeated non-progressing responses and stopped early.');
|
|
1243
1281
|
break;
|
|
1244
1282
|
}
|
|
1283
|
+
// A chat turn ends when the model stops calling tools: that reply is the
|
|
1284
|
+
// answer, and the next message starts the next turn. Unless the host is
|
|
1285
|
+
// still holding something for this turn — a form the person has not
|
|
1286
|
+
// submitted yet — in which case its submission is injected and the loop
|
|
1287
|
+
// continues, so the turn never ends with an unanswered form.
|
|
1288
|
+
if (options.conversational && !finished && toolCallsThisIteration.length === 0) {
|
|
1289
|
+
const injected = options.onIdleTurn ? await options.onIdleTurn() : null;
|
|
1290
|
+
if (injected) {
|
|
1291
|
+
messages.push({ role: 'user', content: injected });
|
|
1292
|
+
}
|
|
1293
|
+
else {
|
|
1294
|
+
finished = true;
|
|
1295
|
+
success = true;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1245
1298
|
// If no tool calls were made, nudge the model to act.
|
|
1246
1299
|
// This handles 'stop', 'other', and any unexpected finish reason.
|
|
1247
|
-
|
|
1248
|
-
const
|
|
1300
|
+
// A chat turn is never nudged: the model simply finished its reply.
|
|
1301
|
+
const recoveryPrompt = options.conversational
|
|
1302
|
+
? null
|
|
1303
|
+
: buildRecoveryPrompt(normalizedOutputVars, repeatedStallCount, toolCallsThisIteration.length === 0);
|
|
1304
|
+
const continuationPrompt = !options.conversational && !finished && getLastMessageRole(messages) === 'assistant'
|
|
1249
1305
|
? buildAssistantContinuationPrompt(normalizedOutputVars)
|
|
1250
1306
|
: null;
|
|
1251
1307
|
const nextPrompt = recoveryPrompt ?? continuationPrompt;
|
|
@@ -1298,11 +1354,36 @@ export async function runAgentLoop(options) {
|
|
|
1298
1354
|
// Extract assistant text responses from the conversation
|
|
1299
1355
|
const assistantTextResponses = [];
|
|
1300
1356
|
for (const m of messages) {
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1357
|
+
// An AI-SDK assistant message carries its text as content *parts*
|
|
1358
|
+
// (`[{type:'text', text:'…'}]`), not a string. Skipping those dropped every
|
|
1359
|
+
// assistant reply from the memory a conversation hands to the next turn (and
|
|
1360
|
+
// left `chat/2` binding an empty string).
|
|
1361
|
+
if (m.role !== 'assistant')
|
|
1362
|
+
continue;
|
|
1363
|
+
const text = messageText(m.content);
|
|
1364
|
+
if (text.trim())
|
|
1365
|
+
assistantTextResponses.push(text);
|
|
1304
1366
|
}
|
|
1305
1367
|
// Add result to persistent messages
|
|
1368
|
+
if (options.conversational) {
|
|
1369
|
+
// A chat turn keeps the conversation, not a task summary: the person's
|
|
1370
|
+
// message and what the agent actually said. No extra summarising model call.
|
|
1371
|
+
return {
|
|
1372
|
+
success: true,
|
|
1373
|
+
outputs,
|
|
1374
|
+
variables,
|
|
1375
|
+
messages: [
|
|
1376
|
+
...conversationHistory
|
|
1377
|
+
.filter((message) => message.role === 'user' || message.role === 'assistant')
|
|
1378
|
+
.map((message) => ({
|
|
1379
|
+
role: message.role,
|
|
1380
|
+
content: typeof message.content === 'string' ? message.content : JSON.stringify(message.content),
|
|
1381
|
+
})),
|
|
1382
|
+
{ role: 'user', content: taskDescription },
|
|
1383
|
+
...assistantTextResponses.map((text) => ({ role: 'assistant', content: text })),
|
|
1384
|
+
],
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1306
1387
|
if (success && Object.keys(variables).length > 0) {
|
|
1307
1388
|
const varSummary = Object.entries(variables)
|
|
1308
1389
|
.map(([k, v]) => `${k}: ${v}`)
|
|
@@ -1347,6 +1428,18 @@ export async function runAgentLoop(options) {
|
|
|
1347
1428
|
messages: persistentMessages,
|
|
1348
1429
|
};
|
|
1349
1430
|
}
|
|
1431
|
+
/** An assistant message's text: a string, or its `{type: 'text'}` content parts. */
|
|
1432
|
+
function messageText(content) {
|
|
1433
|
+
if (typeof content === 'string')
|
|
1434
|
+
return content;
|
|
1435
|
+
if (!Array.isArray(content))
|
|
1436
|
+
return '';
|
|
1437
|
+
return content
|
|
1438
|
+
.map((part) => (part && typeof part === 'object' && part.type === 'text'
|
|
1439
|
+
? String(part.text ?? '')
|
|
1440
|
+
: ''))
|
|
1441
|
+
.join('');
|
|
1442
|
+
}
|
|
1350
1443
|
function getResponseMessages(response) {
|
|
1351
1444
|
if (!response || typeof response !== 'object') {
|
|
1352
1445
|
return [];
|
|
@@ -1360,15 +1453,17 @@ function getResponseMessages(response) {
|
|
|
1360
1453
|
async function buildSystemPrompt(options) {
|
|
1361
1454
|
const toolDescriptions = [];
|
|
1362
1455
|
const normalizedOutputVars = options.outputVars;
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
const
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1456
|
+
if (!options.conversational) {
|
|
1457
|
+
// Add finish tool description
|
|
1458
|
+
toolDescriptions.push('- finish(success: boolean): Signal task completion. Call finish(true) when done successfully, or finish(false) if the task cannot be completed.');
|
|
1459
|
+
// Add set_result tool if we have output variables
|
|
1460
|
+
if (normalizedOutputVars.length > 0) {
|
|
1461
|
+
const varList = normalizedOutputVars.map(v => {
|
|
1462
|
+
const typeStr = v.type === 'array' && v.itemType ? `array<${v.itemType}>` : v.type;
|
|
1463
|
+
return `"${v.name}" (${typeStr})`;
|
|
1464
|
+
}).join(', ');
|
|
1465
|
+
toolDescriptions.push(`- set_result(variable: string, value: any): Store a result value. Variable must be one of: ${varList}`);
|
|
1466
|
+
}
|
|
1372
1467
|
}
|
|
1373
1468
|
// Add user-defined tools
|
|
1374
1469
|
for (const [name, tool] of options.tools) {
|
|
@@ -1400,6 +1495,16 @@ async function buildSystemPrompt(options) {
|
|
|
1400
1495
|
'- If you are stuck, either choose one different tool or call finish(false).',
|
|
1401
1496
|
'- Once enough information exists, stop planning, set results if needed, and finish.',
|
|
1402
1497
|
].join('\n');
|
|
1498
|
+
if (options.conversational) {
|
|
1499
|
+
const chatTemplate = await readSystemPromptAsset('chat', { workspacePath: options.workspacePath });
|
|
1500
|
+
return chatTemplate
|
|
1501
|
+
.replace('{TOOL_DESCRIPTIONS}', toolDescriptions.join('\n'))
|
|
1502
|
+
.replace('{ENVIRONMENT_SECTION}', describeEnvironment({
|
|
1503
|
+
workspacePath: options.workspacePath,
|
|
1504
|
+
environment: options.environment,
|
|
1505
|
+
capabilityTool: options.capabilityTool,
|
|
1506
|
+
}) + describeCurrentTime());
|
|
1507
|
+
}
|
|
1403
1508
|
const template = await readSystemPromptAsset('task', { workspacePath: options.workspacePath });
|
|
1404
1509
|
return template
|
|
1405
1510
|
.replace('{TASK_DESCRIPTION}', options.taskDescription)
|
|
@@ -1409,6 +1514,7 @@ async function buildSystemPrompt(options) {
|
|
|
1409
1514
|
.replace('{ENVIRONMENT_SECTION}', describeEnvironment({
|
|
1410
1515
|
workspacePath: options.workspacePath,
|
|
1411
1516
|
environment: options.environment,
|
|
1517
|
+
capabilityTool: options.capabilityTool,
|
|
1412
1518
|
}) + describeCurrentTime());
|
|
1413
1519
|
}
|
|
1414
1520
|
//# sourceMappingURL=agent.js.map
|