@zhin.js/agent 1.1.39 → 1.1.40
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/lib/assistant/job-storage.d.ts +238 -0
- package/lib/assistant/job-storage.js +143 -0
- package/lib/assistant/job-storage.js.map +1 -0
- package/lib/assistant/job-store.d.ts +7 -0
- package/lib/assistant/job-store.js +41 -3
- package/lib/assistant/job-store.js.map +1 -1
- package/lib/config/perception-config.d.ts +9 -0
- package/lib/config/perception-config.js +27 -0
- package/lib/config/perception-config.js.map +1 -1
- package/lib/context/context-system.d.ts +1 -0
- package/lib/context/context-system.js +8 -8
- package/lib/context/context-system.js.map +1 -1
- package/lib/context/im-turn-context-adapter.js +2 -0
- package/lib/context/im-turn-context-adapter.js.map +1 -1
- package/lib/context/skill-context.d.ts +3 -0
- package/lib/context/skill-context.js +6 -0
- package/lib/context/skill-context.js.map +1 -0
- package/lib/context/turn-envelope.d.ts +4 -0
- package/lib/context/turn-envelope.js +24 -7
- package/lib/context/turn-envelope.js.map +1 -1
- package/lib/context/turn-user-message.d.ts +3 -1
- package/lib/context/turn-user-message.js +14 -1
- package/lib/context/turn-user-message.js.map +1 -1
- package/lib/core/agent-core-run.d.ts +1 -0
- package/lib/core/agent-core-run.js +47 -20
- package/lib/core/agent-core-run.js.map +1 -1
- package/lib/core/structured-reply-recovery.d.ts +6 -2
- package/lib/core/structured-reply-recovery.js +22 -8
- package/lib/core/structured-reply-recovery.js.map +1 -1
- package/lib/core/turn-completion-usage.d.ts +2 -1
- package/lib/core/turn-completion-usage.js +14 -5
- package/lib/core/turn-completion-usage.js.map +1 -1
- package/lib/core/turn-event-mapper.d.ts +1 -1
- package/lib/core/turn-event-mapper.js +8 -5
- package/lib/core/turn-event-mapper.js.map +1 -1
- package/lib/event/turn-event.d.ts +7 -1
- package/lib/event/turn-event.js.map +1 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/media/perception.d.ts +3 -4
- package/lib/media/perception.js +59 -37
- package/lib/media/perception.js.map +1 -1
- package/lib/memory/compaction-runtime.d.ts +3 -2
- package/lib/memory/compaction-runtime.js +22 -14
- package/lib/memory/compaction-runtime.js.map +1 -1
- package/lib/outbound/agent-output.js +2 -0
- package/lib/outbound/agent-output.js.map +1 -1
- package/lib/outbound/chat-failure.d.ts +27 -0
- package/lib/outbound/chat-failure.js +53 -0
- package/lib/outbound/chat-failure.js.map +1 -0
- package/lib/outbound/structured-reply.d.ts +7 -0
- package/lib/outbound/structured-reply.js +52 -16
- package/lib/outbound/structured-reply.js.map +1 -1
- package/lib/plugin-runtime/agent-runtime.js +49 -8
- package/lib/plugin-runtime/agent-runtime.js.map +1 -1
- package/lib/plugin-runtime/ai-completion.d.ts +4 -3
- package/lib/plugin-runtime/ai-completion.js +64 -10
- package/lib/plugin-runtime/ai-completion.js.map +1 -1
- package/lib/plugin-runtime/capability-ingress.js +3 -1
- package/lib/plugin-runtime/capability-ingress.js.map +1 -1
- package/lib/plugin-runtime/deferred-capability-plan.d.ts +4 -1
- package/lib/plugin-runtime/deferred-capability-plan.js +25 -9
- package/lib/plugin-runtime/deferred-capability-plan.js.map +1 -1
- package/lib/plugin-runtime/full-agent-turn-engine.js +1 -0
- package/lib/plugin-runtime/full-agent-turn-engine.js.map +1 -1
- package/lib/plugin-runtime/index.d.ts +2 -0
- package/lib/plugin-runtime/index.js +2 -0
- package/lib/plugin-runtime/index.js.map +1 -1
- package/lib/prompt/assembly.js +0 -9
- package/lib/prompt/assembly.js.map +1 -1
- package/lib/prompt/git-context.js +1 -1
- package/lib/prompt/git-context.js.map +1 -1
- package/lib/prompt/rules/chat-rules.js +8 -9
- package/lib/prompt/rules/chat-rules.js.map +1 -1
- package/lib/prompt/rules/critical-rules.js +10 -10
- package/lib/prompt/rules/critical-rules.js.map +1 -1
- package/lib/prompt/system-prompt.js +4 -5
- package/lib/prompt/system-prompt.js.map +1 -1
- package/lib/security/file-role-policy.js +6 -6
- package/lib/security/file-role-policy.js.map +1 -1
- package/lib/security/policy-facade.js +1 -1
- package/lib/security/policy-facade.js.map +1 -1
- package/lib/security/usage-quota.d.ts +4 -0
- package/lib/security/usage-quota.js +23 -2
- package/lib/security/usage-quota.js.map +1 -1
- package/lib/session/approval-port.d.ts +2 -0
- package/lib/session/approval-port.js.map +1 -1
- package/lib/session/approval-review-agent.d.ts +1 -1
- package/lib/session/approval-review-agent.js +19 -4
- package/lib/session/approval-review-agent.js.map +1 -1
- package/lib/session/turn-ingress-session.js +7 -1
- package/lib/session/turn-ingress-session.js.map +1 -1
- package/lib/tool/tool-approval-gate.js +4 -2
- package/lib/tool/tool-approval-gate.js.map +1 -1
- package/lib/tool/turn-tool-runtime.js +24 -5
- package/lib/tool/turn-tool-runtime.js.map +1 -1
- package/lib/tool-catalog/deferred-turn-controller.js +1 -4
- package/lib/tool-catalog/deferred-turn-controller.js.map +1 -1
- package/lib/trace/context-budget.d.ts +4 -3
- package/lib/trace/context-budget.js +28 -8
- package/lib/trace/context-budget.js.map +1 -1
- package/lib/trace/turn-trace-format.js +4 -1
- package/lib/trace/turn-trace-format.js.map +1 -1
- package/lib/trace/turn-trace.d.ts +6 -0
- package/lib/trace/turn-trace.js +8 -2
- package/lib/trace/turn-trace.js.map +1 -1
- package/lib/trace/turn-usage-log.d.ts +14 -0
- package/lib/trace/turn-usage-log.js +83 -0
- package/lib/trace/turn-usage-log.js.map +1 -0
- package/lib/usage/usage-store.d.ts +199 -0
- package/lib/usage/usage-store.js +121 -0
- package/lib/usage/usage-store.js.map +1 -0
- package/package.json +12 -12
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { createRootPrivateToken, encodeStorageIdentity } from '@zhin.js/plugin-runtime';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { traceScopeTurnId } from '../trace/turn-trace-registry.js';
|
|
4
|
+
const text = { type: 'text', nullable: true };
|
|
5
|
+
const count = { type: 'bigint', nullable: true };
|
|
6
|
+
export const AGENT_USAGE_TURN_MODEL = {
|
|
7
|
+
id: { type: 'text', length: 64, primary: true }, fingerprint: { type: 'text', length: 64, nullable: false },
|
|
8
|
+
owner: text, trace_id: text, turn_id: text, session_key: text, principal_id: text,
|
|
9
|
+
origin_kind: text, endpoint_adapter: text, endpoint_id: text, conversation_kind: text, conversation_id: text,
|
|
10
|
+
parent_kind: text, parent_id: text, thread_id: text, source_id: text,
|
|
11
|
+
selected_provider: text, selected_model: text, status: text,
|
|
12
|
+
started_at: count, ended_at: count, duration_ms: count, call_count: count,
|
|
13
|
+
};
|
|
14
|
+
export const AGENT_USAGE_CALL_MODEL = {
|
|
15
|
+
id: { type: 'text', length: 64, primary: true }, root_id: { type: 'text', length: 64, nullable: false },
|
|
16
|
+
turn_id: text, call_index: { type: 'integer', nullable: false }, provider: text, model: text, stop_reason: text,
|
|
17
|
+
duration_ms: count, input_tokens: count, output_tokens: count, total_tokens: count,
|
|
18
|
+
cache_read_tokens: count, cache_write_tokens: count, reasoning_tokens: count, ended_at: count, root_ended_at: count,
|
|
19
|
+
};
|
|
20
|
+
export const agentUsageStoreToken = createRootPrivateToken('zhin.agent.usage-store', 'Generation-owned structured usage persistence');
|
|
21
|
+
const tokenFields = {
|
|
22
|
+
input_tokens: ['promptTokens', 'input'], output_tokens: ['completionTokens', 'output'], total_tokens: ['totalTokens', 'totalTokens'],
|
|
23
|
+
cache_read_tokens: ['cacheReadTokens', 'cacheRead'], cache_write_tokens: ['cacheWriteTokens', 'cacheWrite'], reasoning_tokens: ['reasoningTokens', 'reasoning'],
|
|
24
|
+
};
|
|
25
|
+
function nonnegative(value) { return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : null; }
|
|
26
|
+
const identity = (value) => value === undefined ? null : encodeStorageIdentity(value);
|
|
27
|
+
const digest = (value) => createHash('sha256').update(JSON.stringify(value)).digest('hex');
|
|
28
|
+
/** Minimal numeric facts, independent of log level and trace archive size limits. */
|
|
29
|
+
export class AgentUsageCollector {
|
|
30
|
+
owner;
|
|
31
|
+
request;
|
|
32
|
+
selected;
|
|
33
|
+
#calls = [];
|
|
34
|
+
#indexes = new Map();
|
|
35
|
+
#startedAt = Date.now();
|
|
36
|
+
#id;
|
|
37
|
+
constructor(owner, request, selected) {
|
|
38
|
+
this.owner = owner;
|
|
39
|
+
this.request = request;
|
|
40
|
+
this.selected = selected;
|
|
41
|
+
this.#id = digest([owner, request.identity.turnId]);
|
|
42
|
+
}
|
|
43
|
+
record(event) {
|
|
44
|
+
if (event.type !== 'usage')
|
|
45
|
+
return;
|
|
46
|
+
const turnId = traceScopeTurnId(event) ?? this.request.identity.turnId;
|
|
47
|
+
const index = (this.#indexes.get(turnId) ?? 0) + 1;
|
|
48
|
+
this.#indexes.set(turnId, index);
|
|
49
|
+
const row = { id: digest([this.#id, turnId, index]), root_id: this.#id, turn_id: identity(turnId), call_index: index,
|
|
50
|
+
provider: event.provider ?? null, model: event.model ?? null, stop_reason: event.stopReason ?? null,
|
|
51
|
+
duration_ms: typeof event.durationMs === 'number' ? nonnegative(Math.round(event.durationMs)) : null, ended_at: Date.now() };
|
|
52
|
+
for (const [column, [source, availability]] of Object.entries(tokenFields)) {
|
|
53
|
+
const value = nonnegative(event.usage[source]);
|
|
54
|
+
const reported = event.usage.reported?.[availability]
|
|
55
|
+
?? (availability === 'input' || availability === 'output' || availability === 'totalTokens' ? value !== null && value > 0 : value !== null);
|
|
56
|
+
row[column] = reported ? value : null;
|
|
57
|
+
}
|
|
58
|
+
this.#calls.push(row);
|
|
59
|
+
}
|
|
60
|
+
finish(status) {
|
|
61
|
+
const endedAt = Date.now(), origin = this.request.origin, im = origin.kind === 'im' ? origin : undefined;
|
|
62
|
+
const turn = { id: this.#id, owner: identity(this.owner), trace_id: identity(this.request.identity.traceId), turn_id: identity(this.request.identity.turnId),
|
|
63
|
+
session_key: identity(this.request.session.key), principal_id: identity(this.request.principal.subjectId),
|
|
64
|
+
origin_kind: origin.kind, endpoint_adapter: identity(im?.conversation?.endpoint.adapter ?? im?.platform), endpoint_id: identity(im?.conversation?.endpoint.id ?? im?.endpoint),
|
|
65
|
+
conversation_kind: im?.conversation?.kind ?? im?.scope ?? null, conversation_id: identity(im?.conversation?.id ?? im?.sceneId), parent_kind: im?.conversation?.parent?.kind ?? null,
|
|
66
|
+
parent_id: identity(im?.conversation?.parent?.id), thread_id: identity(im?.conversation?.threadId ?? im?.threadId),
|
|
67
|
+
source_id: identity(origin.kind === 'schedule' ? origin.jobId : origin.kind === 'a2a' ? origin.taskId : origin.kind === 'http' ? origin.sessionId : origin.kind === 'internal' ? origin.source : undefined),
|
|
68
|
+
selected_provider: this.selected.provider, selected_model: this.selected.model, status,
|
|
69
|
+
started_at: this.#startedAt, ended_at: endedAt, duration_ms: endedAt - this.#startedAt, call_count: this.#calls.length,
|
|
70
|
+
};
|
|
71
|
+
const calls = this.#calls.map(row => ({ ...row, root_ended_at: endedAt }));
|
|
72
|
+
turn.fingerprint = digest([turn, calls]);
|
|
73
|
+
return { turn, calls };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Tables contain no payload JSON, chat content, prompt, tool arguments or error text. */
|
|
77
|
+
export class DatabaseAgentUsageStore {
|
|
78
|
+
database;
|
|
79
|
+
retentionDays;
|
|
80
|
+
now;
|
|
81
|
+
constructor(database, retentionDays = 30, now = Date.now) {
|
|
82
|
+
this.database = database;
|
|
83
|
+
this.retentionDays = retentionDays;
|
|
84
|
+
this.now = now;
|
|
85
|
+
if (!Number.isSafeInteger(retentionDays) || retentionDays <= 0)
|
|
86
|
+
throw new TypeError('ai.usage.retentionDays must be a positive integer');
|
|
87
|
+
if (!database.transaction)
|
|
88
|
+
throw new Error('Agent usage requires transactional database storage');
|
|
89
|
+
}
|
|
90
|
+
async save(record) {
|
|
91
|
+
try {
|
|
92
|
+
await this.database.transaction(async (transaction) => {
|
|
93
|
+
const turns = transaction.model('agent_usage_turns');
|
|
94
|
+
const existing = (await turns.select('fingerprint').where({ id: record.turn.id }))[0];
|
|
95
|
+
if (existing) {
|
|
96
|
+
if (existing.fingerprint !== record.turn.fingerprint)
|
|
97
|
+
throw new Error('Conflicting usage record for the same turn');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
await turns.insert(record.turn);
|
|
101
|
+
for (const call of record.calls)
|
|
102
|
+
await transaction.model('agent_usage_calls').insert(call);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
// A concurrent writer may have committed the same complete record.
|
|
107
|
+
const existing = (await this.database.models.get('agent_usage_turns').select('fingerprint').where({ id: record.turn.id }).limit(1))[0];
|
|
108
|
+
if (existing?.fingerprint === record.turn.fingerprint)
|
|
109
|
+
return;
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async prune() {
|
|
114
|
+
const cutoff = this.now() - this.retentionDays * 86_400_000;
|
|
115
|
+
await this.database.transaction(async (transaction) => {
|
|
116
|
+
await transaction.model('agent_usage_calls').delete().where({ root_ended_at: { $lt: cutoff } });
|
|
117
|
+
await transaction.model('agent_usage_turns').delete().where({ ended_at: { $lt: cutoff } });
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=usage-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-store.js","sourceRoot":"","sources":["../../src/usage/usage-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { createRootPrivateToken, encodeStorageIdentity, type DatabaseHost } from '@zhin.js/plugin-runtime';\nimport { createHash } from 'node:crypto';\nimport type { TurnEvent } from '../event/turn-event.js';\nimport type { TurnRequest } from '../turn/turn-ingress.js';\nimport { traceScopeTurnId } from '../trace/turn-trace-registry.js';\n\nconst text = { type: 'text', nullable: true } as const;\nconst count = { type: 'bigint', nullable: true } as const;\nexport const AGENT_USAGE_TURN_MODEL = {\n id: { type: 'text', length: 64, primary: true }, fingerprint: { type: 'text', length: 64, nullable: false },\n owner: text, trace_id: text, turn_id: text, session_key: text, principal_id: text,\n origin_kind: text, endpoint_adapter: text, endpoint_id: text, conversation_kind: text, conversation_id: text,\n parent_kind: text, parent_id: text, thread_id: text, source_id: text,\n selected_provider: text, selected_model: text, status: text,\n started_at: count, ended_at: count, duration_ms: count, call_count: count,\n} as const;\nexport const AGENT_USAGE_CALL_MODEL = {\n id: { type: 'text', length: 64, primary: true }, root_id: { type: 'text', length: 64, nullable: false },\n turn_id: text, call_index: { type: 'integer', nullable: false }, provider: text, model: text, stop_reason: text,\n duration_ms: count, input_tokens: count, output_tokens: count, total_tokens: count,\n cache_read_tokens: count, cache_write_tokens: count, reasoning_tokens: count, ended_at: count, root_ended_at: count,\n} as const;\nexport type UsageRow = Record<string, string | number | null>;\nexport interface AgentUsageRecord { readonly turn: UsageRow; readonly calls: readonly UsageRow[] }\nexport interface AgentUsageStore { save(record: AgentUsageRecord): Promise<void>; prune(): Promise<void> }\nexport const agentUsageStoreToken = createRootPrivateToken<AgentUsageStore>('zhin.agent.usage-store', 'Generation-owned structured usage persistence');\n\nconst tokenFields = {\n input_tokens: ['promptTokens', 'input'], output_tokens: ['completionTokens', 'output'], total_tokens: ['totalTokens', 'totalTokens'],\n cache_read_tokens: ['cacheReadTokens', 'cacheRead'], cache_write_tokens: ['cacheWriteTokens', 'cacheWrite'], reasoning_tokens: ['reasoningTokens', 'reasoning'],\n} as const;\nfunction nonnegative(value: unknown): number | null { return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : null; }\nconst identity = (value: string | undefined) => value === undefined ? null : encodeStorageIdentity(value);\nconst digest = (value: unknown) => createHash('sha256').update(JSON.stringify(value)).digest('hex');\n\n/** Minimal numeric facts, independent of log level and trace archive size limits. */\nexport class AgentUsageCollector {\n readonly #calls: UsageRow[] = [];\n readonly #indexes = new Map<string, number>();\n readonly #startedAt = Date.now();\n readonly #id: string;\n constructor(private readonly owner: string, private readonly request: TurnRequest,\n private readonly selected: { provider: string; model: string }) {\n this.#id = digest([owner, request.identity.turnId]);\n }\n record(event: TurnEvent): void {\n if (event.type !== 'usage') return;\n const turnId = traceScopeTurnId(event) ?? this.request.identity.turnId;\n const index = (this.#indexes.get(turnId) ?? 0) + 1;\n this.#indexes.set(turnId, index);\n const row: UsageRow = { id: digest([this.#id, turnId, index]), root_id: this.#id, turn_id: identity(turnId), call_index: index,\n provider: event.provider ?? null, model: event.model ?? null, stop_reason: event.stopReason ?? null,\n duration_ms: typeof event.durationMs === 'number' ? nonnegative(Math.round(event.durationMs)) : null, ended_at: Date.now() };\n for (const [column, [source, availability]] of Object.entries(tokenFields)) {\n const value = nonnegative(event.usage[source]);\n const reported = event.usage.reported?.[availability]\n ?? (availability === 'input' || availability === 'output' || availability === 'totalTokens' ? value !== null && value > 0 : value !== null);\n row[column] = reported ? value : null;\n }\n this.#calls.push(row);\n }\n finish(status: string): AgentUsageRecord {\n const endedAt = Date.now(), origin = this.request.origin, im = origin.kind === 'im' ? origin : undefined;\n const turn: UsageRow = { id: this.#id, owner: identity(this.owner), trace_id: identity(this.request.identity.traceId), turn_id: identity(this.request.identity.turnId),\n session_key: identity(this.request.session.key), principal_id: identity(this.request.principal.subjectId),\n origin_kind: origin.kind, endpoint_adapter: identity(im?.conversation?.endpoint.adapter ?? im?.platform), endpoint_id: identity(im?.conversation?.endpoint.id ?? im?.endpoint),\n conversation_kind: im?.conversation?.kind ?? im?.scope ?? null, conversation_id: identity(im?.conversation?.id ?? im?.sceneId), parent_kind: im?.conversation?.parent?.kind ?? null,\n parent_id: identity(im?.conversation?.parent?.id), thread_id: identity(im?.conversation?.threadId ?? im?.threadId),\n source_id: identity(origin.kind === 'schedule' ? origin.jobId : origin.kind === 'a2a' ? origin.taskId : origin.kind === 'http' ? origin.sessionId : origin.kind === 'internal' ? origin.source : undefined),\n selected_provider: this.selected.provider, selected_model: this.selected.model, status,\n started_at: this.#startedAt, ended_at: endedAt, duration_ms: endedAt - this.#startedAt, call_count: this.#calls.length,\n };\n const calls = this.#calls.map(row => ({ ...row, root_ended_at: endedAt }));\n turn.fingerprint = digest([turn, calls]);\n return { turn, calls };\n }\n}\n\n/** Tables contain no payload JSON, chat content, prompt, tool arguments or error text. */\nexport class DatabaseAgentUsageStore implements AgentUsageStore {\n constructor(private readonly database: DatabaseHost, readonly retentionDays = 30, private readonly now = Date.now) {\n if (!Number.isSafeInteger(retentionDays) || retentionDays <= 0) throw new TypeError('ai.usage.retentionDays must be a positive integer');\n if (!database.transaction) throw new Error('Agent usage requires transactional database storage');\n }\n async save(record: AgentUsageRecord): Promise<void> {\n try {\n await this.database.transaction!(async transaction => {\n const turns = transaction.model('agent_usage_turns');\n const existing = (await turns.select('fingerprint').where({ id: record.turn.id }))[0];\n if (existing) {\n if (existing.fingerprint !== record.turn.fingerprint) throw new Error('Conflicting usage record for the same turn');\n return;\n }\n await turns.insert(record.turn);\n for (const call of record.calls) await transaction.model('agent_usage_calls').insert(call);\n });\n } catch (error) {\n // A concurrent writer may have committed the same complete record.\n const existing = (await this.database.models.get('agent_usage_turns')!.select('fingerprint').where({ id: record.turn.id }).limit(1))[0];\n if (existing?.fingerprint === record.turn.fingerprint) return;\n throw error;\n }\n }\n async prune(): Promise<void> {\n const cutoff = this.now() - this.retentionDays * 86_400_000;\n await this.database.transaction!(async transaction => {\n await transaction.model('agent_usage_calls').delete().where({ root_ended_at: { $lt: cutoff } });\n await transaction.model('agent_usage_turns').delete().where({ ended_at: { $lt: cutoff } });\n });\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/agent",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.40",
|
|
4
4
|
"description": "Zhin AI Agent — session, ZhinAgent, init; composes @zhin.js/core providers and tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -90,19 +90,19 @@
|
|
|
90
90
|
"ajv": "^8.18.0",
|
|
91
91
|
"he": "^1.2.0",
|
|
92
92
|
"js-yaml": "^5.2.2",
|
|
93
|
-
"@zhin.js/adapter": "1.1.
|
|
94
|
-
"@zhin.js/agent-feature": "1.1.
|
|
95
|
-
"@zhin.js/ai": "1.1.
|
|
96
|
-
"@zhin.js/core": "1.1.
|
|
97
|
-
"@zhin.js/im-contract": "1.1.
|
|
93
|
+
"@zhin.js/adapter": "1.1.22",
|
|
94
|
+
"@zhin.js/agent-feature": "1.1.9",
|
|
95
|
+
"@zhin.js/ai": "1.1.44",
|
|
96
|
+
"@zhin.js/core": "1.1.50",
|
|
97
|
+
"@zhin.js/im-contract": "1.1.6",
|
|
98
98
|
"@zhin.js/kernel": "1.1.5",
|
|
99
99
|
"@zhin.js/logger": "1.1.2",
|
|
100
|
-
"@zhin.js/mcp-feature": "1.1.
|
|
101
|
-
"@zhin.js/permission": "1.1.
|
|
102
|
-
"@zhin.js/plugin-runtime": "1.1.
|
|
103
|
-
"@zhin.js/prompt-section": "1.1.
|
|
104
|
-
"@zhin.js/skill": "1.1.
|
|
105
|
-
"@zhin.js/tool": "1.1.
|
|
100
|
+
"@zhin.js/mcp-feature": "1.1.9",
|
|
101
|
+
"@zhin.js/permission": "1.1.8",
|
|
102
|
+
"@zhin.js/plugin-runtime": "1.1.16",
|
|
103
|
+
"@zhin.js/prompt-section": "1.1.8",
|
|
104
|
+
"@zhin.js/skill": "1.1.9",
|
|
105
|
+
"@zhin.js/tool": "1.1.9"
|
|
106
106
|
},
|
|
107
107
|
"peerDependencies": {
|
|
108
108
|
"@modelcontextprotocol/sdk": "^1.29.0",
|