@ziggs-ai/agent-sdk 0.37.0 → 0.38.1
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/CHANGELOG.md +3 -0
- package/dist/Agent.d.ts +1 -9
- package/dist/Agent.js +4 -11
- package/dist/brain/claudeCognition.d.ts +1 -1
- package/dist/brain/claudeCognition.js +3 -3
- package/dist/brain/claudeSdkProtocol.js +1 -1
- package/dist/brain/claudeSdkTools.js +1 -1
- package/dist/defineAgent.js +3 -8
- package/dist/formatters/AgreementFormatter.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/platform/inboxLoop.js +6 -1
- package/dist/platform/tools/tier1/protocolRunner.js +6 -0
- package/dist/platform/tools/tier1/protocolTools.js +1 -1
- package/dist/runtime/PromptBuilder.js +1 -1
- package/dist/runtime/runTurn.js +0 -21
- package/dist/shared/fleetModel.d.ts +8 -0
- package/dist/shared/fleetModel.js +16 -0
- package/dist/shared/operatorKeyClaims.d.ts +6 -13
- package/dist/shared/operatorKeyClaims.js +7 -19
- package/dist/shared/runtimeLog.d.ts +4 -16
- package/dist/shared/runtimeLog.js +3 -66
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
### Changed (breaking)
|
|
16
16
|
|
|
17
|
+
- The SDK log level follows `configureApiClient({ logLevel })`. `DEBUG_AGENTPLUS` / `LOG_LEVEL` still apply when the process runs `env-init`, which is what copies them into that config. Setting only the environment, without `configureApiClient`, no longer changes SDK logs.
|
|
18
|
+
- `decodeOperatorKeyClaims` is api-client's decoder. A non-string `boundAgentId` is ignored, and `issuedVia` is kept.
|
|
19
|
+
- The fleet model is `resolveFleetModel`: a per-agent pin, then `LLM_MODEL`, then Sonnet 5.5 (`DEFAULT_MODEL`).
|
|
17
20
|
- Hosted Claude agents load Ziggs tools on demand. Everyday and own tools load up front; every other platform tool is offered by its own name and loaded by the Agent SDK's tool search when the model looks for it. The `tools` / `tool_read` / `tool_write` catalog is gone from the hosted brain.
|
|
18
21
|
- `isHostedCatalogOnly` is now `isHostedDeferred`; `hostedModelTools(all)` takes no executor and returns every tool; `HostedToolExecute` is removed.
|
|
19
22
|
|
package/dist/Agent.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { AgentConfig, Ctx, Workflow } from './types.js';
|
|
|
4
4
|
import { ZiggsBrain, type TickOutput } from './brain/ZiggsBrain.js';
|
|
5
5
|
import { ClaudeBrain, type CognitionKind } from './brain/ClaudeBrain.js';
|
|
6
6
|
import { type BrainSelection } from './brain/index.js';
|
|
7
|
+
export { DEFAULT_MODEL, resolveFleetModel } from './shared/fleetModel.js';
|
|
7
8
|
export type { CognitionKind };
|
|
8
9
|
import { type WaitForIdleResult } from './platform/EventQueue.js';
|
|
9
10
|
import { type NormalizedEvent } from './ingress/normalizeIncoming.js';
|
|
@@ -29,14 +30,6 @@ import { ToolManager } from './tools/ToolManager.js';
|
|
|
29
30
|
import { type ToolDefinition } from './tools/defineTool.js';
|
|
30
31
|
import { OpenAIAdapter } from './adapters/OpenAIAdapter.js';
|
|
31
32
|
import { type AgentNeed } from './tools/needs.js';
|
|
32
|
-
/**
|
|
33
|
-
* The single fleet-wide default model — the one place the fallback lives.
|
|
34
|
-
* Change this (or set `LLM_MODEL`) to move the whole fleet; nothing hardcodes a
|
|
35
|
-
* model anywhere else. The id also picks the provider: a `claude-*` value routes
|
|
36
|
-
* to AnthropicAdapter (+ ANTHROPIC_API_KEY), anything else to OpenAIAdapter — see
|
|
37
|
-
* the `model?.startsWith('claude')` branch in createBackendServices below.
|
|
38
|
-
*/
|
|
39
|
-
export declare const DEFAULT_MODEL = "claude-haiku-4-5";
|
|
40
33
|
/**
|
|
41
34
|
* Given a normalized event, return the sessionId for this agent. Return
|
|
42
35
|
* `null` to skip processing. Lets each Agent define what "session" means —
|
|
@@ -251,7 +244,6 @@ export declare class Agent {
|
|
|
251
244
|
private taskService;
|
|
252
245
|
private agreementService;
|
|
253
246
|
private telemetryClient?;
|
|
254
|
-
private messageSender;
|
|
255
247
|
private seenMessages;
|
|
256
248
|
private stateTimers;
|
|
257
249
|
/** The per-agent inbox long-poll loop — this agent's sole wake source. */
|
package/dist/Agent.js
CHANGED
|
@@ -11,6 +11,8 @@ import { backendWakeGate } from './brain/wakeGate.js';
|
|
|
11
11
|
import { applyBrainToAgentOptions, isClaudeCognition, } from './brain/index.js';
|
|
12
12
|
import { CLAUDE_SDK_TOOLS } from './brain/claudeSdkTools.js';
|
|
13
13
|
import { resolveClaudeModel } from './brain/claudeCognition.js';
|
|
14
|
+
import { resolveFleetModel } from './shared/fleetModel.js';
|
|
15
|
+
export { DEFAULT_MODEL, resolveFleetModel } from './shared/fleetModel.js';
|
|
14
16
|
import { CHAT_TOOLS } from './platform/tools/tier2/chatTools.js';
|
|
15
17
|
import { contextReadTool, openTool, accessExplainTool } from './platform/tools/tier2/contextTools.js';
|
|
16
18
|
import { EventQueue } from './platform/EventQueue.js';
|
|
@@ -39,14 +41,6 @@ import { runtimeLog } from './shared/runtimeLog.js';
|
|
|
39
41
|
import { isTelemetryIngestEnabled, sendTelemetry, } from './platform/telemetryIngest.js';
|
|
40
42
|
import { buildWakeOutcomePayload, classifyWakeOutcome, wakeWasAsked, } from './runtime/wakeOutcome.js';
|
|
41
43
|
import { agreementIdFromWake, formedByFromWake, isHireActivationNotice, shouldSkipAgentFormedHireActivation, } from './brain/hireActivationNotice.js';
|
|
42
|
-
/**
|
|
43
|
-
* The single fleet-wide default model — the one place the fallback lives.
|
|
44
|
-
* Change this (or set `LLM_MODEL`) to move the whole fleet; nothing hardcodes a
|
|
45
|
-
* model anywhere else. The id also picks the provider: a `claude-*` value routes
|
|
46
|
-
* to AnthropicAdapter (+ ANTHROPIC_API_KEY), anything else to OpenAIAdapter — see
|
|
47
|
-
* the `model?.startsWith('claude')` branch in createBackendServices below.
|
|
48
|
-
*/
|
|
49
|
-
export const DEFAULT_MODEL = 'claude-haiku-4-5';
|
|
50
44
|
// ConnectionPool lives in a separate module; resolved via a computed-path
|
|
51
45
|
// dynamic import to avoid a circular import with Agent.
|
|
52
46
|
async function loadConnectionPool() {
|
|
@@ -201,7 +195,6 @@ export class Agent {
|
|
|
201
195
|
taskService;
|
|
202
196
|
agreementService;
|
|
203
197
|
telemetryClient;
|
|
204
|
-
messageSender;
|
|
205
198
|
seenMessages = new SeenMessages();
|
|
206
199
|
stateTimers;
|
|
207
200
|
/** The per-agent inbox long-poll loop — this agent's sole wake source. */
|
|
@@ -227,7 +220,8 @@ export class Agent {
|
|
|
227
220
|
this.options = {
|
|
228
221
|
openaiKey: resolved.openaiKey || process.env.OPENAI_API_KEY,
|
|
229
222
|
anthropicKey: resolved.anthropicKey || process.env.ANTHROPIC_API_KEY,
|
|
230
|
-
model:
|
|
223
|
+
model: resolveFleetModel(resolved.model ||
|
|
224
|
+
(!isLlmAdapter(resolved.services?.llm) ? resolved.services?.llm?.model : undefined)),
|
|
231
225
|
operatorKey: resolved.operatorKey || process.env.ZIGGS_OPERATOR_KEY || undefined,
|
|
232
226
|
agentId: resolved.agentId || '',
|
|
233
227
|
name: resolved.name || null,
|
|
@@ -347,7 +341,6 @@ export class Agent {
|
|
|
347
341
|
this.taskService = services.taskService;
|
|
348
342
|
this.agreementService = services.agreementService;
|
|
349
343
|
this.telemetryClient = services.telemetryClient;
|
|
350
|
-
this.messageSender = messageSender;
|
|
351
344
|
let workflow = this.options.workflow;
|
|
352
345
|
if (!workflow && this.options.states) {
|
|
353
346
|
workflow = {
|
|
@@ -44,7 +44,7 @@ export interface ClaudeQueryOptionsParams {
|
|
|
44
44
|
* Pick the Claude model for a Claude-brain wake. The brain must run a `claude-*`
|
|
45
45
|
* model, but the host's default model is provider-agnostic (an OpenAI id today),
|
|
46
46
|
* so this prefers an explicit `claude-*` id (direct or via `services.llm`) and
|
|
47
|
-
* otherwise falls back to
|
|
47
|
+
* otherwise falls back to {@link DEFAULT_MODEL} — never an OpenAI id.
|
|
48
48
|
*/
|
|
49
49
|
export declare function resolveClaudeModel(preferred?: string, servicesModel?: string): string;
|
|
50
50
|
/**
|
|
@@ -14,19 +14,19 @@
|
|
|
14
14
|
import { SYSTEM_PROMPT_DYNAMIC_BOUNDARY, } from '@anthropic-ai/claude-agent-sdk';
|
|
15
15
|
import { decisionWords } from '@ziggs-ai/api-client';
|
|
16
16
|
import { getBatchEvents } from '../context/batch.js';
|
|
17
|
-
|
|
17
|
+
import { DEFAULT_MODEL } from '../shared/fleetModel.js';
|
|
18
18
|
/**
|
|
19
19
|
* Pick the Claude model for a Claude-brain wake. The brain must run a `claude-*`
|
|
20
20
|
* model, but the host's default model is provider-agnostic (an OpenAI id today),
|
|
21
21
|
* so this prefers an explicit `claude-*` id (direct or via `services.llm`) and
|
|
22
|
-
* otherwise falls back to
|
|
22
|
+
* otherwise falls back to {@link DEFAULT_MODEL} — never an OpenAI id.
|
|
23
23
|
*/
|
|
24
24
|
export function resolveClaudeModel(preferred, servicesModel) {
|
|
25
25
|
if (preferred?.startsWith('claude'))
|
|
26
26
|
return preferred;
|
|
27
27
|
if (servicesModel?.startsWith('claude'))
|
|
28
28
|
return servicesModel;
|
|
29
|
-
return
|
|
29
|
+
return DEFAULT_MODEL;
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* Build the `query()` options for a Claude-brain wake. The lockdown fields are
|
|
@@ -27,7 +27,7 @@ Your prose and final summary are private host notes, not messages to the people
|
|
|
27
27
|
- Closing a task closes the TASK, and only the task. It stores your result where the next agent reads it, queues a wake for whoever the platform addresses, and on an agreement that bills per completed task it meters that one execution. It does not end the hire — a standing agreement stays active for the next task — it does not prove anyone has read you, and it does not prove you were paid. The reply tells you which of those actually happened: report that and nothing beyond it. A completion whose reply you never saw is recovered by READING the task back, never by completing it a second time; your retry carries the same write key, so a redelivered completion no-ops instead of doubling the result, the wake and the charge.
|
|
28
28
|
- Enumerate open work with \`task_list\` (use assignedToMe for your own active tasks).
|
|
29
29
|
- Chat is where you talk to whoever you are working with, and where a human reads what you delivered — sending it to them there is delivery, not duplication. It is not where another AGENT collects a deliverable: that one reads the task result, so a chat message never stands in for closing the task. Deliver into the working conversation the hire already has; do not repeat it into every room you can reach.
|
|
30
|
-
-
|
|
30
|
+
- For replies and follow-ups, send into the original conversation (its chatId). Sending to a person without a chatId selects the main pair room, which may be a different conversation. Missing access is a reason to request the scoped permission, not to silently move the exchange. Use another writable room, or open one with newChat, only for a separate subject. The server refuses what you are not allowed to do, and the refusal says why.
|
|
31
31
|
- When a store listing of yours is claimed (\`resource_changed\` with reason \`proposal_approved\`), call \`chat_open\` with the buyer (actorId / Sender) AND the claimed agreementId. That returns the hire's room, which the server usually made at claim, or opens one when there is none. Greet them only when the agreement accepts messages, then serve the agreement terms. A task-only agreement needs no chat or greeting: wait for assigned tasks and deliver results through tasks. Do not \`chat_send\` to an \`agrn-*\` session id — open a real chat first.
|
|
32
32
|
- When a task you hold carries a deadline or a reminder rule, they are part of the job, not decoration. Never remind the same person sooner than the stated interval or more times than the budget; use \`wake_at\` to come back rather than waiting in place, and re-arm it each time you wake. When the budget is spent, stop asking and say what you have. At the deadline, post what you got and where you are stuck in the room where the question was asked, close the task, and stop — whether or not you got the answer. Nothing stops you from breaking this, which is exactly why it is on you: over-reminding is a breach of the task, not diligence, and every reminder costs a wake.
|
|
33
33
|
- Hand off by completing your task — the platform notifies the next agent.
|
|
@@ -74,7 +74,7 @@ export const chatSendTool = defineTool('chat_send', {
|
|
|
74
74
|
underAgreementId: { type: 'string', description: 'Your run authority, defaulting to the current run in every destination room.' },
|
|
75
75
|
chatId: { type: 'string', description: 'Omit this to send in the chat you were woken in — that is the usual case. Only pass a chatId to send in a DIFFERENT chat, such as one you just opened with chat_open. When chatId is set it wins over `to`.' },
|
|
76
76
|
to: { type: 'string', description: 'User or agent id of someone you already have a conversation with. Sends in that pair room. Naming the person whose message woke you sends in the room that woke you instead, addressed to them. Does not open contact — first contact still needs chat_open. Ignored when chatId is set (chatId wins; `to` is used as receiverId if receiverId is omitted).' },
|
|
77
|
-
receiverId: { type: 'string', description: 'Name someone only when you mean them. Leave it out to write back in this room: one other participant is the recipient, and with several Jev may select one. Otherwise the message stays in the room with no specific wake. To name a masked party, pass its rpb_ ref as it came. Pass human to
|
|
77
|
+
receiverId: { type: 'string', description: 'Name someone only when you mean them. Leave it out to write back in this room: one other participant is the recipient, and with several Jev may select one. Otherwise the message stays in the room with no specific wake. To name a masked party, pass its rpb_ ref as it came. Pass human only for a broadcast to the people in the room; it does not wake assistants or stand-ins. For a reply from a person or their assistant, name that person\'s returned participant id. This does not grant their assistant access or guarantee a reply.' },
|
|
78
78
|
text: { type: 'string', required: true },
|
|
79
79
|
idempotencyKey: { type: 'string', description: 'Reuse for retry-safe resend of the same logical message.' },
|
|
80
80
|
}, async (args, ctx) => {
|
package/dist/defineAgent.js
CHANGED
|
@@ -2,7 +2,7 @@ import { validateWorkflow } from './runtime/validateWorkflow.js';
|
|
|
2
2
|
import { injectKickoffDefault } from './runtime/kickoff.js';
|
|
3
3
|
import { injectTaskIntakeDefault } from './runtime/taskIntake.js';
|
|
4
4
|
import { runtimeLog } from './shared/runtimeLog.js';
|
|
5
|
-
import {
|
|
5
|
+
import { resolveFleetModel } from './shared/fleetModel.js';
|
|
6
6
|
import { normalizeNeeds, toolsForNeeds } from './tools/needs.js';
|
|
7
7
|
import { toolName } from './tools/defineTool.js';
|
|
8
8
|
/**
|
|
@@ -74,13 +74,8 @@ export function defineAgent(input) {
|
|
|
74
74
|
tools[at] = tool;
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
// ONE place the default lives — see Agent). The id also picks the provider
|
|
80
|
-
// (claude-* → Anthropic). No agent hardcodes its own fallback.
|
|
81
|
-
const model = input.services?.llm?.model ||
|
|
82
|
-
process.env.LLM_MODEL ||
|
|
83
|
-
DEFAULT_MODEL;
|
|
77
|
+
// One resolution for every agent: a pin, then LLM_MODEL, then DEFAULT_MODEL.
|
|
78
|
+
const model = resolveFleetModel(input.services?.llm?.model);
|
|
84
79
|
// Strip the structural fields we already consumed; pass through everything
|
|
85
80
|
// else (operatorKey, taskTools, custom keys consumed by Agent).
|
|
86
81
|
const { agentId, description, specialization, services: _services, initial: _initial, states: _states, tools: _tools, operatorKey, taskTools, ...rest } = input;
|
|
@@ -53,7 +53,7 @@ export class AgreementFormatter {
|
|
|
53
53
|
lines.push(`${indent} Proposal: ${proposal['status']}${proposal['respondedBy'] ? ` (by ${proposal['respondedBy']})` : ''}`);
|
|
54
54
|
const money = ag['money'];
|
|
55
55
|
if (typeof money?.['price'] === 'number' && money['price'] > 0) {
|
|
56
|
-
const parts = [`${money['price']}
|
|
56
|
+
const parts = [`${money['price']} hundredths of a point`];
|
|
57
57
|
if (money['paymentStatus'] && money['paymentStatus'] !== 'none')
|
|
58
58
|
parts.push(money['paymentStatus']);
|
|
59
59
|
lines.push(`${indent} Money: ${parts.join(', ')}`);
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export { parseSkill, skillHash, skillRolePrompt, skillReferenceName, skillRefere
|
|
|
14
14
|
export type { ParsedSkill, SkillFile, SkillReference } from './skills/parseSkill.js';
|
|
15
15
|
export { loadSkill, readSkillFiles, assertSkillHash } from './skills/loadSkill.js';
|
|
16
16
|
export { skillReadReferenceTool } from './skills/skillReadReference.js';
|
|
17
|
-
export { Agent, createAgent, createAgentPool, DEFAULT_MODEL } from './Agent.js';
|
|
17
|
+
export { Agent, createAgent, createAgentPool, DEFAULT_MODEL, resolveFleetModel } from './Agent.js';
|
|
18
18
|
export { ZiggsBrain } from './brain/ZiggsBrain.js';
|
|
19
19
|
export { ClaudeBrain } from './brain/ClaudeBrain.js';
|
|
20
20
|
export type { CognitionKind, ClaudeBrainOptions } from './brain/ClaudeBrain.js';
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ export { createMcpAgent, resolveZiggsGatewayTarget, wrapGatewayFetch, ZiggsGatew
|
|
|
16
16
|
export { parseSkill, skillHash, skillRolePrompt, skillReferenceName, skillReferenceOneLine, splitFrontmatter, SkillValidationError, SKILL_MAX_CHARS, } from './skills/parseSkill.js';
|
|
17
17
|
export { loadSkill, readSkillFiles, assertSkillHash } from './skills/loadSkill.js';
|
|
18
18
|
export { skillReadReferenceTool } from './skills/skillReadReference.js';
|
|
19
|
-
export { Agent, createAgent, createAgentPool, DEFAULT_MODEL } from './Agent.js';
|
|
19
|
+
export { Agent, createAgent, createAgentPool, DEFAULT_MODEL, resolveFleetModel } from './Agent.js';
|
|
20
20
|
export { ZiggsBrain } from './brain/ZiggsBrain.js';
|
|
21
21
|
export { ClaudeBrain } from './brain/ClaudeBrain.js';
|
|
22
22
|
// The exact strings a Claude-brain wake sends: the shared protocol block, the
|
|
@@ -7,7 +7,12 @@ function log(label, msg) {
|
|
|
7
7
|
runtimeLog.info(label, msg);
|
|
8
8
|
}
|
|
9
9
|
function inboxClient(deps) {
|
|
10
|
-
return new InboxClient(deps.creds.operatorKey, deps.creds.agentId, deps.baseUrl, deps.creds.instanceId
|
|
10
|
+
return new InboxClient(deps.creds.operatorKey, deps.creds.agentId, deps.baseUrl, deps.creds.instanceId, {
|
|
11
|
+
clientSessionId: deps.creds.clientSessionId,
|
|
12
|
+
workspaceIds: deps.creds.workspaceIds,
|
|
13
|
+
app: deps.creds.app,
|
|
14
|
+
sessionName: deps.creds.sessionName,
|
|
15
|
+
});
|
|
11
16
|
}
|
|
12
17
|
async function releaseInboxHostBestEffort(deps) {
|
|
13
18
|
try {
|
|
@@ -255,6 +255,12 @@ async function proposeAgreement(services, payload, chatId, writeKeys = null) {
|
|
|
255
255
|
// propose resolves to the already-created agreement server-side instead of
|
|
256
256
|
// minting a duplicate proposal. Keyed on what the proposal writes, so
|
|
257
257
|
// multiple proposals in one wake stay distinct.
|
|
258
|
+
// A standing listing is published by a person or the deploy.
|
|
259
|
+
// A broadcast with a provider is that listing. A request omits providerId.
|
|
260
|
+
// A named counterparty is a direct proposal and stays.
|
|
261
|
+
if (isBroadcastTarget(payload.proposedTo) && payload.providerId) {
|
|
262
|
+
throw new Error('A standing listing is published by a person or the deploy. Broadcast without providerId to post a request, or name a counterparty to propose terms inside a deal.');
|
|
263
|
+
}
|
|
258
264
|
const idempotencyKey = writeKeys?.agreementProposeKey({
|
|
259
265
|
proposedTo: payload.proposedTo,
|
|
260
266
|
providerId: payload.providerId,
|
|
@@ -60,7 +60,7 @@ function handlerFor(toolName) {
|
|
|
60
60
|
return result;
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
-
export const agreementProposeTool = defineTool('agreement_propose', { description: { type: 'string', required: true }, proposedTo: { type: 'string', required: true }, engagementKind: { type: 'string', enum: ['hire', 'service'], description: 'Contract type. Defaults to service. For a bilateral trust link, use link_propose.' }, parentAgreementId: 'string', providerId: { type: 'string', description: AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION }, price: { type: 'number', description: 'Price in POINTS, as an integer of hundredths — 500 means ϟ5.00. Convert both ways: a human asking for "ϟ2 per task" means 200, not 2. ϟ is the points symbol, not a hundredth.' }, lifecycle: lifecycleParam, expiresAt: 'string', maxExecutions: 'integer', conversationAllowance: { type: 'number', description: 'Incoming-message limit shared across covered rooms; omitted on new agreements means unlimited.' }, billing: { type: 'string', enum: ['total', 'per_task'], description: "How price reads: 'total' (default, escrowed and paid at the end) or 'per_task' (a rate settled as each task completes — standing agreements only, and the default for a hire)." }, agreementDescription: 'string' }, handlerFor('agreement_propose'), { description: 'Propose an agreement — direct, broadcast, or link; there are no separate publish tools. Engagement precedence (posted-first): 1) REUSE an active agreement on matching terms, 2) CLAIM the counterparty\'s listing (marketplace_view → agreement_claim; never counter a listing), 3) POST a request broadcast here when nothing listed fits, 4) direct-propose ONLY for bespoke terms, renegotiation, or commissioning a named counterparty with no listing — most published agents are claim-only and refuse direct proposals with a pointer at their listing. Direction is stated, never guessed: providerId = your own id ("I work, you pay") or providerId = proposedTo ("you work, I pay") on direct proposals. Broadcast with proposedTo="everyone" (fully public) or "org" (your org only)
|
|
63
|
+
export const agreementProposeTool = defineTool('agreement_propose', { description: { type: 'string', required: true }, proposedTo: { type: 'string', required: true }, engagementKind: { type: 'string', enum: ['hire', 'service'], description: 'Contract type. Defaults to service. For a bilateral trust link, use link_propose.' }, parentAgreementId: 'string', providerId: { type: 'string', description: AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION }, price: { type: 'number', description: 'Price in POINTS, as an integer of hundredths — 500 means ϟ5.00. Convert both ways: a human asking for "ϟ2 per task" means 200, not 2. ϟ is the points symbol, not a hundredth.' }, lifecycle: lifecycleParam, expiresAt: 'string', maxExecutions: 'integer', conversationAllowance: { type: 'number', description: 'Incoming-message limit shared across covered rooms; omitted on new agreements means unlimited.' }, billing: { type: 'string', enum: ['total', 'per_task'], description: "How price reads: 'total' (default, escrowed and paid at the end) or 'per_task' (a rate settled as each task completes — standing agreements only, and the default for a hire)." }, agreementDescription: 'string' }, handlerFor('agreement_propose'), { description: 'Propose an agreement — direct, broadcast, or link; there are no separate publish tools. Engagement precedence (posted-first): 1) REUSE an active agreement on matching terms, 2) CLAIM the counterparty\'s listing (marketplace_view → agreement_claim; never counter a listing), 3) POST a request broadcast here when nothing listed fits, 4) direct-propose ONLY for bespoke terms, renegotiation, or commissioning a named counterparty with no listing — most published agents are claim-only and refuse direct proposals with a pointer at their listing. Direction is stated, never guessed: providerId = your own id ("I work, you pay") or providerId = proposedTo ("you work, I pay") on direct proposals. Broadcast with proposedTo="everyone" (fully public) or "org" (your org only) and no providerId posts a REQUEST any agent may claim. A person or the deploy publishes a standing listing; this agent does not. For a bilateral trust link, use link_propose: it takes an email or an agent id, or neither for a share link. engagementKind defaults to service. Agreements are STANDING by default (no expiry, unlimited tasks under one agreement); set expiresAt or maxExecutions only when the engagement should end on its own.', isAgreementCreation: true });
|
|
64
64
|
export const agreementSubcontractTool = defineTool('agreement_subcontract', agreementSubcontractCapability.params, handlerFor('agreement_subcontract'), { description: agreementSubcontractCapability.descriptions.sdk, isAgreementCreation: true });
|
|
65
65
|
export const agreementRespondTool = defineTool('agreement_respond', { agreementId: { type: 'string', required: true }, action: { type: 'string', required: true, enum: ['approve', 'reject'] } }, handlerFor('agreement_respond'), { description: 'Approve or reject a pending DIRECT agreement proposal addressed to you. Open broadcasts (requests, standing offers, link invites) have no personal approval slot — claim those with agreement_claim instead, or ignore them to pass. ONE exception: a hand-off that pins YOU as provider carries your pending approval even as an open broadcast — approving consents to serving whoever claims it (the row stays open for claims); rejecting cancels the hand-off. Ignoring it leaves the hand-off unclaimable, so always respond.' });
|
|
66
66
|
export const agreementClaimTool = defineTool('agreement_claim', agreementClaimCapability.params, handlerFor('agreement_claim'), { description: agreementClaimCapability.descriptions.sdk });
|
|
@@ -206,7 +206,7 @@ ${this._renderDecisionSchemaFromActions(actions, senderMeta, ctxObj, omitMessage
|
|
|
206
206
|
}
|
|
207
207
|
const money = ag.money;
|
|
208
208
|
if (typeof money?.price === 'number' && money.price > 0) {
|
|
209
|
-
lines.push(` Price: ${money.price}
|
|
209
|
+
lines.push(` Price: ${money.price} hundredths of a point (${money.paymentStatus})`);
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
lines.push('');
|
package/dist/runtime/runTurn.js
CHANGED
|
@@ -493,27 +493,6 @@ export async function runTurn(input) {
|
|
|
493
493
|
return { outcome, toolResults, llmCalls: llmCallsTotal, tokens: { total: tokensTotal, input: tokensInput, output: tokensOutput } };
|
|
494
494
|
}
|
|
495
495
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
496
|
-
function extractIncomingMessageText(event) {
|
|
497
|
-
if (!event)
|
|
498
|
-
return '';
|
|
499
|
-
const parts = [];
|
|
500
|
-
const push = (v) => {
|
|
501
|
-
if (typeof v === 'string' && v.trim())
|
|
502
|
-
parts.push(v.trim());
|
|
503
|
-
};
|
|
504
|
-
push(event.text);
|
|
505
|
-
push(event.message);
|
|
506
|
-
const agreement = event.agreement;
|
|
507
|
-
if (agreement) {
|
|
508
|
-
const terms = agreement.terms;
|
|
509
|
-
push(terms?.description);
|
|
510
|
-
push(JSON.stringify(agreement));
|
|
511
|
-
}
|
|
512
|
-
const task = event.task;
|
|
513
|
-
if (task)
|
|
514
|
-
push(JSON.stringify(task));
|
|
515
|
-
return parts.join('\n');
|
|
516
|
-
}
|
|
517
496
|
function normalizeContextSnapshot(raw) {
|
|
518
497
|
if (!raw || typeof raw !== 'object') {
|
|
519
498
|
return { history: [], agreements: [], agents: [], users: [] };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one model table. Sonnet 5.5 is the default.
|
|
3
|
+
* A per-agent pin wins, then `LLM_MODEL`, then {@link DEFAULT_MODEL}.
|
|
4
|
+
* The id also picks the provider: `claude-*` routes to Anthropic.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_MODEL = "claude-sonnet-5-5";
|
|
7
|
+
/** Pin, then `LLM_MODEL`, then {@link DEFAULT_MODEL}. */
|
|
8
|
+
export declare function resolveFleetModel(pinned?: string): string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one model table. Sonnet 5.5 is the default.
|
|
3
|
+
* A per-agent pin wins, then `LLM_MODEL`, then {@link DEFAULT_MODEL}.
|
|
4
|
+
* The id also picks the provider: `claude-*` routes to Anthropic.
|
|
5
|
+
*/
|
|
6
|
+
export const DEFAULT_MODEL = 'claude-sonnet-5-5';
|
|
7
|
+
/** Pin, then `LLM_MODEL`, then {@link DEFAULT_MODEL}. */
|
|
8
|
+
export function resolveFleetModel(pinned) {
|
|
9
|
+
const pin = pinned?.trim();
|
|
10
|
+
if (pin)
|
|
11
|
+
return pin;
|
|
12
|
+
const fromEnv = process.env.LLM_MODEL?.trim();
|
|
13
|
+
if (fromEnv)
|
|
14
|
+
return fromEnv;
|
|
15
|
+
return DEFAULT_MODEL;
|
|
16
|
+
}
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Client-side peek at an operator key
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* collapses the operator multiplex to its one agent and 403s every other
|
|
6
|
-
* per-agent loop, so a large fleet quietly watches a single agent.
|
|
2
|
+
* Client-side peek at an operator key. The decoder lives in api-client (it
|
|
3
|
+
* keeps `issuedVia` and ignores a non-string `boundAgentId`, and it does not
|
|
4
|
+
* use Node's Buffer). This file re-exports it and keeps the fleet warning.
|
|
7
5
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
ownerId?: string;
|
|
12
|
-
boundAgentId?: string | null;
|
|
13
|
-
exp?: number;
|
|
14
|
-
}
|
|
15
|
-
export declare function decodeOperatorKeyClaims(token: string): OperatorKeyClaims | null;
|
|
6
|
+
import { decodeOperatorKeyClaims } from '@ziggs-ai/api-client';
|
|
7
|
+
export { decodeOperatorKeyClaims };
|
|
8
|
+
export type { OperatorKeyClaims } from '@ziggs-ai/api-client';
|
|
16
9
|
/**
|
|
17
10
|
* The startup check: warn (never refuse — a one-agent launcher on a
|
|
18
11
|
* bound key is legitimate) when the fleet's control key is bound to a single
|
|
@@ -1,22 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return {
|
|
9
|
-
type: payload.type,
|
|
10
|
-
keyId: payload.keyId,
|
|
11
|
-
ownerId: payload.ownerId,
|
|
12
|
-
boundAgentId: payload.boundAgentId ?? null,
|
|
13
|
-
exp: payload.exp,
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Client-side peek at an operator key. The decoder lives in api-client (it
|
|
3
|
+
* keeps `issuedVia` and ignores a non-string `boundAgentId`, and it does not
|
|
4
|
+
* use Node's Buffer). This file re-exports it and keeps the fleet warning.
|
|
5
|
+
*/
|
|
6
|
+
import { decodeOperatorKeyClaims } from '@ziggs-ai/api-client';
|
|
7
|
+
export { decodeOperatorKeyClaims };
|
|
20
8
|
/**
|
|
21
9
|
* The startup check: warn (never refuse — a one-agent launcher on a
|
|
22
10
|
* bound key is legitimate) when the fleet's control key is bound to a single
|
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Env (first match wins for the debug shortcut):
|
|
6
|
-
* - `DEBUG_AGENTPLUS=1` or `AGENTPLUS_DEBUG=1` → threshold `debug`
|
|
7
|
-
* - `LOG_LEVEL` or `AGENTPLUS_LOG_LEVEL` → `debug` | `info` | `warn` | `error` | `silent`
|
|
8
|
-
* (`silent` keeps only `error` output)
|
|
2
|
+
* The SDK follows `configureApiClient({ logLevel })`. The level table lives in
|
|
3
|
+
* api-client; this file only re-exports it so existing imports keep working.
|
|
9
4
|
*/
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
export declare function resetRuntimeLogLevelCache(): void;
|
|
13
|
-
export declare const runtimeLog: {
|
|
14
|
-
debug(scope: string, msg: string, ...rest: unknown[]): void;
|
|
15
|
-
info(scope: string, msg: string, ...rest: unknown[]): void;
|
|
16
|
-
warn(scope: string, msg: string, ...rest: unknown[]): void;
|
|
17
|
-
error(scope: string, msg: string, ...rest: unknown[]): void;
|
|
18
|
-
};
|
|
5
|
+
export { runtimeLog, resetRuntimeLogLevelCache, } from '@ziggs-ai/api-client';
|
|
6
|
+
export type { RuntimeLogLevel } from '@ziggs-ai/api-client';
|
|
@@ -1,68 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Env (first match wins for the debug shortcut):
|
|
6
|
-
* - `DEBUG_AGENTPLUS=1` or `AGENTPLUS_DEBUG=1` → threshold `debug`
|
|
7
|
-
* - `LOG_LEVEL` or `AGENTPLUS_LOG_LEVEL` → `debug` | `info` | `warn` | `error` | `silent`
|
|
8
|
-
* (`silent` keeps only `error` output)
|
|
2
|
+
* The SDK follows `configureApiClient({ logLevel })`. The level table lives in
|
|
3
|
+
* api-client; this file only re-exports it so existing imports keep working.
|
|
9
4
|
*/
|
|
10
|
-
|
|
11
|
-
debug: 0,
|
|
12
|
-
info: 1,
|
|
13
|
-
warn: 2,
|
|
14
|
-
error: 3,
|
|
15
|
-
};
|
|
16
|
-
function parseThreshold() {
|
|
17
|
-
if (process.env.DEBUG_AGENTPLUS === '1' || process.env.AGENTPLUS_DEBUG === '1') {
|
|
18
|
-
return SEVERITY.debug;
|
|
19
|
-
}
|
|
20
|
-
const raw = (process.env.LOG_LEVEL ||
|
|
21
|
-
process.env.AGENTPLUS_LOG_LEVEL ||
|
|
22
|
-
'info').toLowerCase();
|
|
23
|
-
if (raw === 'silent' || raw === 'none')
|
|
24
|
-
return SEVERITY.error;
|
|
25
|
-
if (raw === 'debug' || raw === 'trace')
|
|
26
|
-
return SEVERITY.debug;
|
|
27
|
-
if (raw === 'warn')
|
|
28
|
-
return SEVERITY.warn;
|
|
29
|
-
if (raw === 'error')
|
|
30
|
-
return SEVERITY.error;
|
|
31
|
-
return SEVERITY.info;
|
|
32
|
-
}
|
|
33
|
-
let cachedThreshold = null;
|
|
34
|
-
function threshold() {
|
|
35
|
-
if (cachedThreshold === null)
|
|
36
|
-
cachedThreshold = parseThreshold();
|
|
37
|
-
return cachedThreshold;
|
|
38
|
-
}
|
|
39
|
-
/** Test hook: re-read env after `process.env` mutations. */
|
|
40
|
-
export function resetRuntimeLogLevelCache() {
|
|
41
|
-
cachedThreshold = null;
|
|
42
|
-
}
|
|
43
|
-
function shouldEmit(level) {
|
|
44
|
-
return SEVERITY[level] >= threshold();
|
|
45
|
-
}
|
|
46
|
-
function fmt(scope, msg) {
|
|
47
|
-
return `[${scope}] ${msg}`;
|
|
48
|
-
}
|
|
49
|
-
export const runtimeLog = {
|
|
50
|
-
debug(scope, msg, ...rest) {
|
|
51
|
-
if (!shouldEmit('debug'))
|
|
52
|
-
return;
|
|
53
|
-
console.log(fmt(scope, msg), ...rest);
|
|
54
|
-
},
|
|
55
|
-
info(scope, msg, ...rest) {
|
|
56
|
-
if (!shouldEmit('info'))
|
|
57
|
-
return;
|
|
58
|
-
console.log(fmt(scope, msg), ...rest);
|
|
59
|
-
},
|
|
60
|
-
warn(scope, msg, ...rest) {
|
|
61
|
-
if (!shouldEmit('warn'))
|
|
62
|
-
return;
|
|
63
|
-
console.warn(fmt(scope, msg), ...rest);
|
|
64
|
-
},
|
|
65
|
-
error(scope, msg, ...rest) {
|
|
66
|
-
console.error(fmt(scope, msg), ...rest);
|
|
67
|
-
},
|
|
68
|
-
};
|
|
5
|
+
export { runtimeLog, resetRuntimeLogLevelCache, } from '@ziggs-ai/api-client';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/agent-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.38.1",
|
|
4
4
|
"description": "Agent framework SDK for building autonomous agents on the Ziggs platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@anthropic-ai/claude-agent-sdk": "^0.3.284",
|
|
27
27
|
"@anthropic-ai/sdk": "^0.110.0",
|
|
28
28
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
29
|
-
"@ziggs-ai/api-client": "0.
|
|
29
|
+
"@ziggs-ai/api-client": "0.37.1",
|
|
30
30
|
"ajv": "^8.17.1",
|
|
31
31
|
"dotenv": "^17.2.3",
|
|
32
32
|
"openai": "^4.0.0",
|