@volter/supercode-orchestrator 0.4.159 → 0.5.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/README.md +16 -5
- package/adapters/chat-sdk.mjs +4 -1
- package/adapters/rh2.mjs +18 -20
- package/agent-home.mjs +35 -0
- package/agent-profiles.mjs +53 -0
- package/agents.mjs +443 -0
- package/bin/agent-door.mjs +53 -0
- package/bin/runtime-door.mjs +23 -0
- package/bin/runtime.mjs +59 -4
- package/board/agent-declarations.mjs +29 -0
- package/board/ci.mjs +6 -1
- package/board/cli.mjs +158 -31
- package/board/dispatch.mjs +304 -124
- package/board/engine.mjs +30 -10
- package/board/event-fleet.mjs +59 -0
- package/board/event-relay.mjs +45 -0
- package/board/event-stream.mjs +104 -0
- package/board/incidents.mjs +57 -0
- package/board/published.mjs +86 -0
- package/board/runtime-door.mjs +12 -0
- package/board/store.mjs +39 -6
- package/board/tools.mjs +1 -0
- package/board/wake.mjs +17 -56
- package/board/workflow.mjs +28 -7
- package/board/workspace.mjs +18 -15
- package/commands.mjs +2 -2
- package/conversations.mjs +108 -0
- package/cron.mjs +30 -4
- package/gates.mjs +3 -2
- package/hermes-cli.mjs +19 -2
- package/index.d.ts +43 -2
- package/index.mjs +4 -0
- package/installed-apps.mjs +52 -0
- package/ir.mjs +3 -3
- package/kanban-worker.mjs +16 -6
- package/loop.mjs +211 -21
- package/mcp/bridge.mjs +13 -2
- package/mcp/tools.mjs +17 -0
- package/mcp/verbs.mjs +29 -7
- package/ontology.d.ts +246 -2
- package/operator.mjs +6 -1
- package/package.json +2 -2
- package/reducer.mjs +133 -28
- package/webhook.mjs +8 -4
package/agents.mjs
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
// Teams identity, orchestrator intent and assignments: one boundary, joined by the immutable agent id.
|
|
2
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
3
|
+
import { mkdirSync } from 'node:fs';
|
|
4
|
+
import { join, basename } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
8
|
+
import { runtimeDoor } from './board/runtime-door.mjs';
|
|
9
|
+
import { resolveAgentProfile } from './agent-profiles.mjs';
|
|
10
|
+
import { compareAgentProfile } from '@volter/teams/agent-profile';
|
|
11
|
+
const entry=fileURLToPath(new URL('./bin/agent-door.mjs',import.meta.url));
|
|
12
|
+
export function agentDoor(op,args=[],{context,timeout=25000}={}){
|
|
13
|
+
const reply=spawnSync(process.execPath,[entry],{input:JSON.stringify({op,args,context}),encoding:'utf8',timeout,maxBuffer:4*1024*1024});
|
|
14
|
+
if(reply.status!==0){let detail;try{detail=JSON.parse(reply.stderr);}catch{detail={message:reply.error?.message??String(reply.stderr).slice(-1000)};}throw Object.assign(new Error(detail.message??'Teams agent door unavailable'),detail);}
|
|
15
|
+
return JSON.parse(reply.stdout);
|
|
16
|
+
}
|
|
17
|
+
/** Teams is not configured, not reachable, or no longer accepts this login: identity stays local until it syncs.
|
|
18
|
+
* A refusal Teams decided (forbidden, conflict, not found, invalid) is never read as absence. */
|
|
19
|
+
export function teamsUnavailable(error){
|
|
20
|
+
if(error?.status!=null)return error.status>=500||error.status===401;
|
|
21
|
+
return !['forbidden','conflict','not_found','invalid_request','revision_mismatch','idempotency_conflict'].includes(error?.code);
|
|
22
|
+
}
|
|
23
|
+
/** The Org agent identity belongs to: the selected Teams context, or this home's local store when there is none. */
|
|
24
|
+
export function agentScope(context){
|
|
25
|
+
try{return agentDoor('scope',[],{context});}
|
|
26
|
+
catch(error){if(teamsUnavailable(error))return {server:'local',org:'local',principal:null,offline:true,reason:error.message};throw error;}
|
|
27
|
+
}
|
|
28
|
+
function store(root){
|
|
29
|
+
mkdirSync(root,{recursive:true,mode:0o700});const db=new DatabaseSync(join(root,'agent-state.sqlite'));
|
|
30
|
+
db.exec(`PRAGMA busy_timeout=5000; PRAGMA journal_mode=WAL;
|
|
31
|
+
CREATE TABLE IF NOT EXISTS agent_intents(org TEXT NOT NULL,id TEXT NOT NULL,key TEXT NOT NULL,profile_ref TEXT NOT NULL,profile_json TEXT NOT NULL,declared INTEGER NOT NULL DEFAULT 0,declaration_json TEXT,created_at INTEGER NOT NULL,PRIMARY KEY(org,id),UNIQUE(org,key));
|
|
32
|
+
CREATE TABLE IF NOT EXISTS agent_declaration_heads(org TEXT NOT NULL,key TEXT NOT NULL,agent_id TEXT NOT NULL,generation INTEGER NOT NULL DEFAULT 0,PRIMARY KEY(org,key));
|
|
33
|
+
CREATE TABLE IF NOT EXISTS agent_assignments(org TEXT NOT NULL,id TEXT NOT NULL,agent_id TEXT NOT NULL,kind TEXT NOT NULL,target TEXT NOT NULL,role TEXT NOT NULL,state TEXT NOT NULL,started_at INTEGER NOT NULL,ended_at INTEGER,PRIMARY KEY(org,id));
|
|
34
|
+
CREATE INDEX IF NOT EXISTS agent_active_assignments ON agent_assignments(org,agent_id,state);
|
|
35
|
+
CREATE TABLE IF NOT EXISTS agent_end_outbox(org TEXT NOT NULL,agent_id TEXT NOT NULL,reason TEXT NOT NULL,created_at INTEGER NOT NULL,PRIMARY KEY(org,agent_id));
|
|
36
|
+
CREATE TABLE IF NOT EXISTS agent_runtime_sessions(org TEXT NOT NULL,runtime_ref TEXT NOT NULL,session_ref TEXT NOT NULL,PRIMARY KEY(org,runtime_ref));
|
|
37
|
+
CREATE TABLE IF NOT EXISTS agent_runs(org TEXT NOT NULL,agent_id TEXT NOT NULL,session_ref TEXT NOT NULL,machine TEXT,run_id TEXT,profile_json TEXT,published INTEGER NOT NULL DEFAULT 0,ended_at INTEGER,end_reason TEXT,main INTEGER NOT NULL DEFAULT 1,starter_session TEXT,usage_json TEXT,PRIMARY KEY(org,session_ref));`);
|
|
38
|
+
return db;
|
|
39
|
+
}
|
|
40
|
+
const digest=value=>createHash('sha256').update(value).digest('hex');
|
|
41
|
+
const minted=(key,machine)=>{
|
|
42
|
+
const reply=runtimeDoor(machine,'harness.v1.agents.mint',{key});
|
|
43
|
+
if(reply.code===0)return JSON.parse(reply.stdout).id;
|
|
44
|
+
// A host without the machine daemon (a container running only the orchestrator) mints the same
|
|
45
|
+
// globally unique shape here; the intent row keyed by this key is what keeps the id stable.
|
|
46
|
+
if(machine===null&&/machine_offline|ENOENT|ECONNREFUSED|no machine daemon/i.test(reply.stderr))return `agent_${randomBytes(16).toString('hex')}`;
|
|
47
|
+
throw new Error(`agent id mint unavailable: ${reply.stderr.slice(-500)}`);
|
|
48
|
+
};
|
|
49
|
+
export function agentIntent(root,org,id){const db=store(root);try{const row=db.prepare('SELECT * FROM agent_intents WHERE org=? AND id=?').get(org,id);return row?{...row,profile:JSON.parse(row.profile_json),assignments:db.prepare("SELECT * FROM agent_assignments WHERE org=? AND agent_id=? AND state='active'").all(org,id)}:null;}finally{db.close();}}
|
|
50
|
+
export function assignAgent(root,org,id,{kind,target,role}){
|
|
51
|
+
const db=store(root),key=digest(JSON.stringify([kind,target,role]));try{db.prepare("INSERT INTO agent_assignments(org,id,agent_id,kind,target,role,state,started_at) VALUES (?,?,?,?,?,?,'active',?) ON CONFLICT(org,id) DO UPDATE SET agent_id=excluded.agent_id,state='active',ended_at=NULL").run(org,key,id,kind,target,role,Date.now());return key;}finally{db.close();}
|
|
52
|
+
}
|
|
53
|
+
export function activeAgentAssignments(root){const db=store(root);try{return db.prepare("SELECT * FROM agent_assignments WHERE state='active'").all();}finally{db.close();}}
|
|
54
|
+
export function reassignAgent(root,org,assignment,to,{context}={}) {
|
|
55
|
+
const target=agentDoor('management',[to],{context}).data;
|
|
56
|
+
const db=store(root);
|
|
57
|
+
try {
|
|
58
|
+
const old=db.prepare("SELECT * FROM agent_assignments WHERE org=? AND id=? AND state='active'").get(org,assignment);
|
|
59
|
+
if(!old)throw new Error('active assignment not found');
|
|
60
|
+
if(old.agent_id!==to)agentDoor('management',[old.agent_id],{context});
|
|
61
|
+
db.exec('BEGIN IMMEDIATE');
|
|
62
|
+
const moved=db.prepare("UPDATE agent_assignments SET agent_id=? WHERE org=? AND id=? AND agent_id=? AND state='active'").run(to,org,assignment,old.agent_id);
|
|
63
|
+
if(moved.changes!==1)throw new Error('assignment changed while reassigning it');
|
|
64
|
+
db.prepare('DELETE FROM agent_end_outbox WHERE org=? AND agent_id=?').run(org,to);
|
|
65
|
+
if(old.agent_id!==to&&!db.prepare("SELECT 1 FROM agent_assignments WHERE org=? AND agent_id=? AND state='active'").get(org,old.agent_id))
|
|
66
|
+
db.prepare('INSERT OR IGNORE INTO agent_end_outbox(org,agent_id,reason,created_at) VALUES (?,?,?,?)').run(org,old.agent_id,`last assignment reassigned to ${to}`,Date.now());
|
|
67
|
+
db.exec('COMMIT');
|
|
68
|
+
return {...old,agent_id:to,profile:target.profile};
|
|
69
|
+
}catch(error){try{db.exec('ROLLBACK');}catch{}throw error;}finally{db.close();}
|
|
70
|
+
}
|
|
71
|
+
export function finishAgentAssignment(root,org,assignment,reason){
|
|
72
|
+
const db=store(root);try{
|
|
73
|
+
db.exec('BEGIN IMMEDIATE');
|
|
74
|
+
const row=db.prepare("SELECT * FROM agent_assignments WHERE org=? AND id=? AND state='active'").get(org,assignment);
|
|
75
|
+
if(!row){db.exec('COMMIT');return;}
|
|
76
|
+
const at=Date.now();db.prepare("UPDATE agent_assignments SET state='ended',ended_at=? WHERE org=? AND id=?").run(at,org,assignment);
|
|
77
|
+
if(!db.prepare("SELECT 1 FROM agent_assignments WHERE org=? AND agent_id=? AND state='active'").get(org,row.agent_id))db.prepare('INSERT OR IGNORE INTO agent_end_outbox(org,agent_id,reason,created_at) VALUES (?,?,?,?)').run(org,row.agent_id,reason,at);
|
|
78
|
+
db.exec('COMMIT');
|
|
79
|
+
}catch(error){try{db.exec('ROLLBACK');}catch{}throw error;}finally{db.close();}
|
|
80
|
+
}
|
|
81
|
+
export function synchronizeAgentEnds(root,org,{context}={}){
|
|
82
|
+
const db=store(root),pending=[];
|
|
83
|
+
try{
|
|
84
|
+
for(const row of db.prepare('SELECT * FROM agent_end_outbox WHERE org=? ORDER BY created_at LIMIT 100').all(org)){
|
|
85
|
+
if(db.prepare("SELECT 1 FROM agent_assignments WHERE org=? AND agent_id=? AND state='active'").get(org,row.agent_id)){db.prepare('DELETE FROM agent_end_outbox WHERE org=? AND agent_id=?').run(org,row.agent_id);continue;}
|
|
86
|
+
if(db.prepare('SELECT 1 FROM agent_runs WHERE org=? AND agent_id=? AND published=0').get(org,row.agent_id)){pending.push({agent:row.agent_id,error:'session ownership publication remains pending'});continue;}
|
|
87
|
+
try{
|
|
88
|
+
agentDoor('end',[row.agent_id,row.reason,digest(`${org}/${row.agent_id}/end/${row.created_at}`)],{context});
|
|
89
|
+
db.prepare('UPDATE agent_runs SET ended_at=COALESCE(ended_at,?),end_reason=COALESCE(end_reason,?) WHERE org=? AND agent_id=?').run(Date.now(),row.reason,org,row.agent_id);
|
|
90
|
+
db.prepare('DELETE FROM agent_end_outbox WHERE org=? AND agent_id=?').run(org,row.agent_id);
|
|
91
|
+
}
|
|
92
|
+
catch(error){pending.push({agent:row.agent_id,error:error.message});}
|
|
93
|
+
}
|
|
94
|
+
return pending;
|
|
95
|
+
}finally{db.close();}
|
|
96
|
+
}
|
|
97
|
+
/** Mint and retain intent before any network call. Offline declarations keep their immutable id for sync. */
|
|
98
|
+
export function declareAgentIntent({root,org,server,profiles,profile,key,machine=null,refresh=true}) {
|
|
99
|
+
const intended=resolveAgentProfile(profiles,profile),stable=`${server}/${org}/${key}`,db=store(root);
|
|
100
|
+
try {
|
|
101
|
+
const head=db.prepare('SELECT * FROM agent_declaration_heads WHERE org=? AND key=?').get(org,stable);
|
|
102
|
+
let row=head?db.prepare('SELECT * FROM agent_intents WHERE org=? AND id=?').get(org,head.agent_id):db.prepare('SELECT * FROM agent_intents WHERE org=? AND key=?').get(org,stable);
|
|
103
|
+
const fresh=!row;
|
|
104
|
+
if(!row){
|
|
105
|
+
const id=minted(stable,machine);
|
|
106
|
+
db.prepare('INSERT INTO agent_intents(org,id,key,profile_ref,profile_json,declared,created_at) VALUES (?,?,?,?,?,0,?) ON CONFLICT(org,key) DO NOTHING').run(org,id,stable,profile,JSON.stringify(intended),Date.now());
|
|
107
|
+
row=db.prepare('SELECT * FROM agent_intents WHERE org=? AND key=?').get(org,stable);
|
|
108
|
+
}
|
|
109
|
+
db.prepare('INSERT OR IGNORE INTO agent_declaration_heads(org,key,agent_id) VALUES (?,?,?)').run(org,stable,row.id);
|
|
110
|
+
if(refresh)db.prepare('UPDATE agent_intents SET profile_ref=?,profile_json=? WHERE org=? AND id=?').run(profile,JSON.stringify(intended),org,row.id);
|
|
111
|
+
return {id:row.id,key:row.key,baseKey:stable,declared:!!row.declared,intended:refresh?intended:JSON.parse(row.profile_json),fresh,org};
|
|
112
|
+
}finally{db.close();}
|
|
113
|
+
}
|
|
114
|
+
function adoptAgentIntent(root,intent,identity){
|
|
115
|
+
const db=store(root);try{
|
|
116
|
+
db.exec('BEGIN IMMEDIATE');
|
|
117
|
+
const existing=db.prepare('SELECT * FROM agent_intents WHERE org=? AND id=?').get(intent.org,identity.id);
|
|
118
|
+
if(!existing)db.prepare('INSERT INTO agent_intents(org,id,key,profile_ref,profile_json,declared,created_at) VALUES (?,?,?,?,?,1,?)').run(intent.org,identity.id,`${intent.baseKey}/adopted/${identity.id}`,identity.profile,JSON.stringify(intent.intended),Date.now());
|
|
119
|
+
db.prepare('UPDATE agent_declaration_heads SET agent_id=? WHERE org=? AND key=?').run(identity.id,intent.org,intent.baseKey);
|
|
120
|
+
db.exec('COMMIT');
|
|
121
|
+
return {...intent,id:identity.id,key:existing?.key??`${intent.baseKey}/adopted/${identity.id}`,declared:true};
|
|
122
|
+
}catch(error){try{db.exec('ROLLBACK');}catch{}throw error;}finally{db.close();}
|
|
123
|
+
}
|
|
124
|
+
function nextAgentGeneration(root,intent,machine){
|
|
125
|
+
const db=store(root);try{
|
|
126
|
+
db.exec('BEGIN IMMEDIATE');
|
|
127
|
+
const head=db.prepare('SELECT * FROM agent_declaration_heads WHERE org=? AND key=?').get(intent.org,intent.baseKey);
|
|
128
|
+
if(head.agent_id!==intent.id){
|
|
129
|
+
const row=db.prepare('SELECT * FROM agent_intents WHERE org=? AND id=?').get(intent.org,head.agent_id);db.exec('COMMIT');
|
|
130
|
+
return {...intent,id:row.id,key:row.key,declared:!!row.declared};
|
|
131
|
+
}
|
|
132
|
+
const generation=head.generation+1,key=`${intent.baseKey}/generation/${generation}`,id=minted(key,machine);
|
|
133
|
+
db.prepare('INSERT INTO agent_intents(org,id,key,profile_ref,profile_json,created_at) VALUES (?,?,?,?,?,?)').run(intent.org,id,key,intent.intended.profile,JSON.stringify(intent.intended),Date.now());
|
|
134
|
+
db.prepare('UPDATE agent_declaration_heads SET agent_id=?,generation=? WHERE org=? AND key=?').run(id,generation,intent.org,intent.baseKey);
|
|
135
|
+
db.exec('COMMIT');return {...intent,id,key,declared:false};
|
|
136
|
+
}catch(error){try{db.exec('ROLLBACK');}catch{}throw error;}finally{db.close();}
|
|
137
|
+
}
|
|
138
|
+
function synchronizeIntent(intent,{root,context,body}) {
|
|
139
|
+
let identity;
|
|
140
|
+
if(intent.declared)identity=agentDoor('get',[intent.id],{context}).data;
|
|
141
|
+
else {
|
|
142
|
+
try{identity=agentDoor('declare',[{...body,id:intent.id},digest(intent.key)],{context}).data;}
|
|
143
|
+
catch(error){if(error.code==='idempotency_conflict')identity=agentDoor('get',[intent.id],{context}).data;else throw error;}
|
|
144
|
+
identity=agentDoor('get',[intent.id],{context}).data;
|
|
145
|
+
const db=store(root);try{db.prepare('UPDATE agent_intents SET declared=1 WHERE org=? AND id=?').run(intent.org,intent.id);}finally{db.close();}
|
|
146
|
+
}
|
|
147
|
+
if(identity.state!=='active')throw new Error(`agent ${identity.path} is ${identity.state}: ${identity.suspension_reason??identity.end_reason??'unavailable'}`);
|
|
148
|
+
if(body.profile!==identity.profile)identity=agentDoor('profile',[identity.id,body.profile,identity.revision],{context}).data;
|
|
149
|
+
if(body.parent!==undefined&&body.parent!==identity.parent)identity=agentDoor('reparent',[identity.id,body.parent,identity.revision],{context}).data;
|
|
150
|
+
return identity;
|
|
151
|
+
}
|
|
152
|
+
export function ensureRootAgent(options) {
|
|
153
|
+
const {root,org,context,profile=options.profiles.default?'default':null}=options;
|
|
154
|
+
if(!profile)throw new Error('declare the Org root with a named profile before launching card agents');
|
|
155
|
+
let intent=declareAgentIntent({...options,profile,key:'root'});
|
|
156
|
+
let identity;
|
|
157
|
+
try{identity=agentDoor('root',[],{context}).data;}
|
|
158
|
+
catch(error){
|
|
159
|
+
if(error.status!==404)throw error;
|
|
160
|
+
try{identity=synchronizeIntent(intent,{root,context,body:{name:basename(root),profile,root:true}});}
|
|
161
|
+
catch(conflict){if(conflict.status!==409)throw conflict;identity=agentDoor('root',[],{context}).data;}
|
|
162
|
+
}
|
|
163
|
+
if(identity.state==='ended'){
|
|
164
|
+
if(intent.id!==identity.id)intent=adoptAgentIntent(root,intent,identity);
|
|
165
|
+
intent=nextAgentGeneration(root,intent,options.machine);
|
|
166
|
+
identity=synchronizeIntent(intent,{root,context,body:{name:identity.name,profile,root:true}});
|
|
167
|
+
}
|
|
168
|
+
if(intent.id!==identity.id)adoptAgentIntent(root,intent,identity);
|
|
169
|
+
// Another admitted manager may have declared the root first; its server id remains authoritative.
|
|
170
|
+
if(identity.state!=='active')throw new Error('the Org root agent is not active');
|
|
171
|
+
return identity;
|
|
172
|
+
}
|
|
173
|
+
/** Cold starts and relaunches use the same local intent and public declaration. Reviewer and implementer keys differ. */
|
|
174
|
+
export function ensureCardAgent(options) {
|
|
175
|
+
const {root,org,profiles,profile,card,role,sponsor=null,context}=options;
|
|
176
|
+
const assigned=activeAgentAssignments(root).find(item=>item.org===org&&item.kind==='card'&&item.target===card&&item.role===role);
|
|
177
|
+
// A locally minted agent that has not reached Teams yet is declared below under the same key and id.
|
|
178
|
+
if(assigned&&agentIntent(root,org,assigned.agent_id)?.declared!==0) {
|
|
179
|
+
const identity=agentDoor('get',[assigned.agent_id],{context}).data;
|
|
180
|
+
if(identity.state==='active'){
|
|
181
|
+
const intended=resolveAgentProfile(profiles,identity.profile);
|
|
182
|
+
const db=store(root);try{db.prepare('UPDATE agent_intents SET profile_ref=?,profile_json=? WHERE org=? AND id=?').run(identity.profile,JSON.stringify(intended),org,identity.id);}finally{db.close();}
|
|
183
|
+
return {identity,intended,assignment:assigned.id,
|
|
184
|
+
assignments:activeAgentAssignments(root).filter(item=>item.org===org&&item.agent_id===identity.id),org};
|
|
185
|
+
}
|
|
186
|
+
if(identity.state!=='ended')throw new Error(`card's assigned agent is ${identity.state}`);
|
|
187
|
+
finishAgentAssignment(root,org,assigned.id,`agent ${identity.id} is ended`);
|
|
188
|
+
}
|
|
189
|
+
let intent=declareAgentIntent({...options,key:`card/${card}/${role}`});
|
|
190
|
+
const rootAgent=ensureRootAgent({...options,profile:profiles.default?'default':profile});
|
|
191
|
+
if(!intent.declared){
|
|
192
|
+
const existing=agentDoor('find',[`${card}-${role}`,rootAgent.id],{context}).data;
|
|
193
|
+
if(existing){
|
|
194
|
+
intent=adoptAgentIntent(root,intent,existing);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if(intent.declared&&agentDoor('get',[intent.id],{context}).data.state==='ended')intent=nextAgentGeneration(root,intent,options.machine);
|
|
198
|
+
const identity=synchronizeIntent(intent,{root,context,body:{name:`${card}-${role}`,parent:rootAgent.id,sponsor,profile,...(options.starterSession?{starter_session:options.starterSession}:{})}});
|
|
199
|
+
const assignment=assignAgent(root,org,identity.id,{kind:'card',target:card,role});
|
|
200
|
+
return {identity,intended:intent.intended,assignment,assignments:[{kind:'card',target:card,role}],org};
|
|
201
|
+
}
|
|
202
|
+
/** Starting a named profile declares its standing agent; bindings are sessions of that identity. */
|
|
203
|
+
export function ensureProfileAgent(options){
|
|
204
|
+
const {root,org,profiles,profile,context,agent:declared=null,declarations={}}=options;
|
|
205
|
+
if(declared&&declared!==profile){
|
|
206
|
+
// A declared agent (the IR's `agents`) runs as a shared profile under its own identity and parent.
|
|
207
|
+
const decl=declarations[declared]??{};
|
|
208
|
+
const rootAgent=ensureRootAgent({...options,profile:profiles.default?'default':profile});
|
|
209
|
+
const parent=decl.parent?ensureProfileAgent({...options,profile:declarations[decl.parent]?.profile??decl.parent,agent:decl.parent}).identity:rootAgent;
|
|
210
|
+
let declaration=declareAgentIntent({...options,key:`agent/${declared}`});
|
|
211
|
+
if(!declaration.declared){
|
|
212
|
+
const existing=agentDoor('find',[declared,parent.id],{context}).data;
|
|
213
|
+
if(existing)declaration=adoptAgentIntent(root,declaration,existing);
|
|
214
|
+
}
|
|
215
|
+
if(declaration.declared&&agentDoor('get',[declaration.id],{context}).data.state==='ended')declaration=nextAgentGeneration(root,declaration,options.machine);
|
|
216
|
+
const identity=synchronizeIntent(declaration,{root,context,body:{name:declared,parent:parent.id,profile,...(decl.sponsor?{sponsor:decl.sponsor}:{})}});
|
|
217
|
+
const assignment=assignAgent(root,org,identity.id,{kind:'agent',target:declared,role:'declared'});
|
|
218
|
+
return {identity,intended:declaration.intended,assignment,assignments:[{kind:'agent',target:declared,role:'declared'}],org};
|
|
219
|
+
}
|
|
220
|
+
const rootAgent=ensureRootAgent({...options,profile:profiles.default?'default':profile});
|
|
221
|
+
let identity=rootAgent,intent;
|
|
222
|
+
if(profile===(profiles.default?'default':profile))intent=agentIntent(root,org,identity.id)?.profile;
|
|
223
|
+
else{
|
|
224
|
+
// Profile ancestry and agent parentage are the same intended narrowing tree.
|
|
225
|
+
// Resolve first to reject a cycle before declaring any parent along it.
|
|
226
|
+
resolveAgentProfile(profiles,profile);
|
|
227
|
+
const parentProfile=profiles[profile].parent;
|
|
228
|
+
const parent=parentProfile?ensureProfileAgent({...options,profile:parentProfile}).identity:rootAgent;
|
|
229
|
+
let declaration=declareAgentIntent({...options,key:`profile/${profile}`});
|
|
230
|
+
if(!declaration.declared){
|
|
231
|
+
const existing=agentDoor('find',[profile,parent.id],{context}).data;
|
|
232
|
+
if(existing)declaration=adoptAgentIntent(root,declaration,existing);
|
|
233
|
+
}
|
|
234
|
+
if(declaration.declared&&agentDoor('get',[declaration.id],{context}).data.state==='ended')declaration=nextAgentGeneration(root,declaration,options.machine);
|
|
235
|
+
identity=synchronizeIntent(declaration,{root,context,body:{name:profile,parent:parent.id,profile}});
|
|
236
|
+
intent=declaration.intended;
|
|
237
|
+
}
|
|
238
|
+
const assignment=assignAgent(root,org,identity.id,{kind:'profile',target:profile,role:'profile'});
|
|
239
|
+
return {identity,intended:intent??resolveAgentProfile(profiles,profile),assignment,assignments:[{kind:'profile',target:profile,role:'profile'}],org};
|
|
240
|
+
}
|
|
241
|
+
/** An explicit fork declares a child; a routine helper launch keeps its starter's identity. */
|
|
242
|
+
export function ensureForkAgent(options) {
|
|
243
|
+
const {root,org,profiles,parent,session,name,key,context}=options;
|
|
244
|
+
const managed=agentDoor('management',[parent],{context}).data;
|
|
245
|
+
const source=agentDoor('session',[session],{context}).data;
|
|
246
|
+
if(source.agent?.id!==parent)throw new Error('fork source is not owned by the declared parent');
|
|
247
|
+
const parentIntent=agentIntent(root,org,parent)?.profile??resolveAgentProfile(profiles,managed.profile);
|
|
248
|
+
let intent=declareAgentIntent({...options,profile:managed.profile,key:`fork/${parent}/${key}`,refresh:false});
|
|
249
|
+
if(intent.declared&&agentDoor('get',[intent.id],{context}).data.state==='ended')throw new Error('this fork identity ended; declare a new fork key');
|
|
250
|
+
// The snapshot copies configuration only. Memory stays the new child's own empty state.
|
|
251
|
+
const intended=structuredClone(intent.fresh?parentIntent:intent.intended);
|
|
252
|
+
const db=store(root);try{db.prepare('UPDATE agent_intents SET profile_json=? WHERE org=? AND id=?').run(JSON.stringify(intended),org,intent.id);}finally{db.close();}
|
|
253
|
+
const identity=synchronizeIntent(intent,{root,context,body:{name,parent,profile:managed.profile,starter_session:session}});
|
|
254
|
+
const assignment=assignAgent(root,org,identity.id,{kind:'fork',target:session,role:key});
|
|
255
|
+
return {identity,intended,assignment,assignments:[{kind:'fork',target:session,role:key}],org};
|
|
256
|
+
}
|
|
257
|
+
export function agentRunForKey(root,org,agent,key) {
|
|
258
|
+
const db=store(root);try{return db.prepare('SELECT * FROM agent_runs WHERE org=? AND agent_id=? AND run_id=? ORDER BY rowid DESC LIMIT 1').get(org,agent,key)??null;}finally{db.close();}
|
|
259
|
+
}
|
|
260
|
+
function recordDeclaration(root,org,id,declaration){
|
|
261
|
+
const db=store(root);try{db.prepare('UPDATE agent_intents SET declaration_json=? WHERE org=? AND id=? AND declared=0').run(JSON.stringify(declaration),org,id);}finally{db.close();}
|
|
262
|
+
}
|
|
263
|
+
/** Situation 16: no reachable Teams. The daemon-minted id and retained intent stand in for the declaration,
|
|
264
|
+
* which synchronizeLocalAgents later makes under the same id. Nothing is granted from this local record. */
|
|
265
|
+
function localAgent(options,{key,name,declaration,assignment,parent=null,starter}){
|
|
266
|
+
const {root,org,server,profiles,profile,machine=null}=options;
|
|
267
|
+
const rootProfile=profiles.default?'default':profile;
|
|
268
|
+
const rootIntent=declareAgentIntent({root,org,server,profiles,profile:rootProfile,key:'root',machine,refresh:false});
|
|
269
|
+
recordDeclaration(root,org,rootIntent.id,{kind:'root',profile:rootProfile});
|
|
270
|
+
const intent=key==='root'?rootIntent:declareAgentIntent({root,org,server,profiles,profile,key,machine});
|
|
271
|
+
if(key!=='root')recordDeclaration(root,org,intent.id,declaration);
|
|
272
|
+
const above=parent??(key==='root'?null:{id:rootIntent.id,path:basename(root)});
|
|
273
|
+
const identity={id:intent.id,kind:'agent',org,name,path:above?`${above.path}/${name}`:name,parent:above?.id??null,
|
|
274
|
+
lineage:{starter},sponsor:options.sponsor??null,explicit_sponsor:options.sponsor??null,profile,state:'active',
|
|
275
|
+
synced:false,main_session:null,revision:0};
|
|
276
|
+
const assigned=assignAgent(root,org,intent.id,assignment);
|
|
277
|
+
return {identity,intended:intent.intended,assignment:assigned,assignments:[assignment],org,synced:false};
|
|
278
|
+
}
|
|
279
|
+
export function localCardAgent(options){
|
|
280
|
+
const {card,role,profile}=options;
|
|
281
|
+
return localAgent(options,{key:`card/${card}/${role}`,name:`${card}-${role}`,assignment:{kind:'card',target:card,role},
|
|
282
|
+
declaration:{kind:'card',card,role,profile,sponsor:options.sponsor??null,starterSession:options.starterSession??null},
|
|
283
|
+
starter:options.starterSession?{kind:'session',id:options.starterSession}:{kind:'automation',id:`board:${basename(options.root)}`}});
|
|
284
|
+
}
|
|
285
|
+
export function localProfileAgent(options){
|
|
286
|
+
const {root,profiles,profile,agent:declared=null,declarations={}}=options,rootProfile=profiles.default?'default':profile;
|
|
287
|
+
const starter={kind:'automation',id:`orchestrator:${basename(root)}`};
|
|
288
|
+
if(declared&&declared!==profile){
|
|
289
|
+
const decl=declarations[declared]??{};
|
|
290
|
+
return localAgent({...options,sponsor:decl.sponsor??null},{key:`agent/${declared}`,name:declared,assignment:{kind:'agent',target:declared,role:'declared'},
|
|
291
|
+
declaration:{kind:'declared',agent:declared,profile},starter});
|
|
292
|
+
}
|
|
293
|
+
if(profile===rootProfile)return localAgent(options,{key:'root',name:basename(root),assignment:{kind:'profile',target:profile,role:'profile'},declaration:{kind:'root',profile},starter});
|
|
294
|
+
resolveAgentProfile(profiles,profile);
|
|
295
|
+
const parentProfile=profiles[profile].parent,parent=parentProfile&&parentProfile!==rootProfile?localProfileAgent({...options,profile:parentProfile}).identity:null;
|
|
296
|
+
return localAgent(options,{key:`profile/${profile}`,name:profile,parent,assignment:{kind:'profile',target:profile,role:'profile'},declaration:{kind:'profile',profile},starter});
|
|
297
|
+
}
|
|
298
|
+
/** A local identity for a retained run: its id, intent and assignments, without a Teams record. */
|
|
299
|
+
export function localAgentRecord(root,org,id){
|
|
300
|
+
const intent=agentIntent(root,org,id);if(!intent)return null;
|
|
301
|
+
const declaration=intent.declaration_json?JSON.parse(intent.declaration_json):{};
|
|
302
|
+
const name=declaration.kind==='card'?`${declaration.card}-${declaration.role}`:declaration.kind==='profile'?declaration.profile:declaration.kind==='declared'?declaration.agent:basename(root);
|
|
303
|
+
return {identity:{id,kind:'agent',org,name,path:declaration.kind==='root'?name:`${basename(root)}/${name}`,parent:null,lineage:{starter:null},
|
|
304
|
+
sponsor:declaration.sponsor??null,profile:intent.profile_ref,state:'active',synced:!!intent.declared,main_session:null,revision:0},
|
|
305
|
+
intended:intent.profile,assignments:intent.assignments,org,synced:!!intent.declared};
|
|
306
|
+
}
|
|
307
|
+
/** Earlier sessions this home ran for an agent, for a relaunch's pointers when Teams cannot list them. */
|
|
308
|
+
export function localAgentSessions(root,org,id){
|
|
309
|
+
const db=store(root);try{return db.prepare('SELECT session_ref AS session,machine,ended_at,end_reason FROM agent_runs WHERE org=? AND agent_id=? ORDER BY rowid DESC LIMIT 200').all(org,id);}finally{db.close();}
|
|
310
|
+
}
|
|
311
|
+
/** Move identities minted before any Teams context into the Org that is now selected, keeping their ids. */
|
|
312
|
+
function adoptLocalOrg(root,scope){
|
|
313
|
+
const db=store(root);
|
|
314
|
+
try{
|
|
315
|
+
if(!db.prepare("SELECT 1 FROM agent_intents WHERE org='local' LIMIT 1").get())return;
|
|
316
|
+
db.exec('BEGIN IMMEDIATE');
|
|
317
|
+
const from='local/local/',to=`${scope.server}/${scope.org}/`,rekey=key=>key.startsWith(from)?to+key.slice(from.length):key;
|
|
318
|
+
const ids=new Map();
|
|
319
|
+
for(const row of db.prepare("SELECT * FROM agent_intents WHERE org='local'").all()){
|
|
320
|
+
// An identity the Org already declared for the same key wins; the local id folds into it.
|
|
321
|
+
const existing=db.prepare('SELECT id FROM agent_intents WHERE org=? AND key=?').get(scope.org,rekey(row.key));
|
|
322
|
+
ids.set(row.id,existing?.id??row.id);
|
|
323
|
+
if(!existing)db.prepare('INSERT INTO agent_intents(org,id,key,profile_ref,profile_json,declared,declaration_json,created_at) VALUES (?,?,?,?,?,0,?,?)').run(scope.org,row.id,rekey(row.key),row.profile_ref,row.profile_json,row.declaration_json,row.created_at);
|
|
324
|
+
}
|
|
325
|
+
for(const head of db.prepare("SELECT * FROM agent_declaration_heads WHERE org='local'").all())
|
|
326
|
+
db.prepare('INSERT OR IGNORE INTO agent_declaration_heads(org,key,agent_id,generation) VALUES (?,?,?,?)').run(scope.org,rekey(head.key),ids.get(head.agent_id)??head.agent_id,head.generation);
|
|
327
|
+
for(const [old,id] of ids)for(const table of ['agent_assignments','agent_runs','agent_end_outbox'])
|
|
328
|
+
db.prepare(`UPDATE OR IGNORE ${table} SET org=?,agent_id=? WHERE org='local' AND agent_id=?`).run(scope.org,id,old);
|
|
329
|
+
db.prepare("UPDATE OR IGNORE agent_runtime_sessions SET org=? WHERE org='local'").run(scope.org);
|
|
330
|
+
for(const table of ['agent_intents','agent_declaration_heads','agent_assignments','agent_runs','agent_end_outbox','agent_runtime_sessions'])db.prepare(`DELETE FROM ${table} WHERE org='local'`).run();
|
|
331
|
+
db.exec('COMMIT');
|
|
332
|
+
}catch(error){try{db.exec('ROLLBACK');}catch{}throw error;}finally{db.close();}
|
|
333
|
+
}
|
|
334
|
+
/** Declare every locally minted identity once Teams is reachable, under the id its sessions already carry. */
|
|
335
|
+
export function synchronizeLocalAgents({root,profiles,context,machine=null,declarations={}}){
|
|
336
|
+
const scope=agentScope(context);if(scope.offline)return [];
|
|
337
|
+
adoptLocalOrg(root,scope);
|
|
338
|
+
const db=store(root);let rows;
|
|
339
|
+
try{rows=db.prepare('SELECT * FROM agent_intents WHERE org=? AND declared=0 AND declaration_json IS NOT NULL ORDER BY created_at').all(scope.org);}finally{db.close();}
|
|
340
|
+
const pending=[],base={root,org:scope.org,server:scope.server,profiles,context,machine};
|
|
341
|
+
for(const row of rows){
|
|
342
|
+
const declaration=JSON.parse(row.declaration_json);
|
|
343
|
+
try{
|
|
344
|
+
if(declaration.kind==='root')ensureRootAgent({...base,profile:declaration.profile});
|
|
345
|
+
else if(declaration.kind==='card')ensureCardAgent({...base,profile:declaration.profile,card:declaration.card,role:declaration.role,sponsor:declaration.sponsor,starterSession:declaration.starterSession});
|
|
346
|
+
else if(declaration.kind==='profile')ensureProfileAgent({...base,profile:declaration.profile});
|
|
347
|
+
else if(declaration.kind==='declared')ensureProfileAgent({...base,profile:declaration.profile,agent:declaration.agent,declarations});
|
|
348
|
+
}catch(error){if(!teamsUnavailable(error))pending.push({agent:row.id,error:error.message});else return [...pending,{agent:row.id,error:error.message}];}
|
|
349
|
+
}
|
|
350
|
+
return pending;
|
|
351
|
+
}
|
|
352
|
+
/** A managed runtime may report its native id after opening. Keep the lease pointer out of the catalogue. */
|
|
353
|
+
export function recordNativeAgentSession(root,runtimeRef,session) {
|
|
354
|
+
const owner=agentRunForSession(root,[runtimeRef]);
|
|
355
|
+
if(!owner||owner.session_ref===session)return owner;
|
|
356
|
+
recordAgentRun(root,owner.org,owner.agent_id,{session,machine:owner.machine,run:owner.run_id,
|
|
357
|
+
profile:owner.profile_json?JSON.parse(owner.profile_json):null,main:owner.main===1,starterSession:owner.starter_session});
|
|
358
|
+
const db=store(root);try{
|
|
359
|
+
db.exec('BEGIN IMMEDIATE');
|
|
360
|
+
db.prepare('INSERT INTO agent_runtime_sessions(org,runtime_ref,session_ref) VALUES (?,?,?) ON CONFLICT(org,runtime_ref) DO UPDATE SET session_ref=excluded.session_ref').run(owner.org,runtimeRef,session);
|
|
361
|
+
// A published native session remains history; an unpublished lease-only row is not a session.
|
|
362
|
+
db.prepare('DELETE FROM agent_runs WHERE org=? AND session_ref=? AND published=0').run(owner.org,runtimeRef);
|
|
363
|
+
db.exec('COMMIT');
|
|
364
|
+
}catch(error){try{db.exec('ROLLBACK');}catch{}throw error;}finally{db.close();}
|
|
365
|
+
return agentRunForSession(root,[runtimeRef]);
|
|
366
|
+
}
|
|
367
|
+
/** Join an observed native session through the public catalogue; unknown catalogue state remains pending. */
|
|
368
|
+
export function synchronizeAgentRun(root,org,row,{context,intended}={}) {
|
|
369
|
+
const response=agentDoor('ownSession',[row.agent_id,{session:row.session_ref,main:row.main!==0&&row.main!==false,...(row.starter_session?{starter_session:row.starter_session}:{})},digest(`${org}/${row.agent_id}/${row.session_ref}`)],{context});
|
|
370
|
+
const intent=agentIntent(root,org,row.agent_id);
|
|
371
|
+
const runtime=agentDoor('bindContext',[row.agent_id,row.session_ref,row.machine,intent?.assignments??[],intended??intent?.profile.resolved],{context});
|
|
372
|
+
publishAgentRun(root,org,row.session_ref);
|
|
373
|
+
return {...response.data,runtime};
|
|
374
|
+
}
|
|
375
|
+
export function recordAgentRun(root,org,id,{session,machine=null,run,profile=null,main=true,starterSession=null}){
|
|
376
|
+
const db=store(root);try{
|
|
377
|
+
db.exec('BEGIN IMMEDIATE');
|
|
378
|
+
const old=db.prepare('SELECT agent_id FROM agent_runs WHERE org=? AND session_ref=?').get(org,session);
|
|
379
|
+
if(old&&old.agent_id!==id)throw new Error('local session ownership cannot change agent identity');
|
|
380
|
+
db.prepare('INSERT INTO agent_runs(org,agent_id,session_ref,machine,run_id,profile_json,main,starter_session) VALUES (?,?,?,?,?,?,?,?) ON CONFLICT(org,session_ref) DO UPDATE SET machine=excluded.machine,run_id=excluded.run_id,profile_json=COALESCE(excluded.profile_json,agent_runs.profile_json),main=excluded.main,starter_session=COALESCE(agent_runs.starter_session,excluded.starter_session) WHERE agent_runs.machine IS NOT excluded.machine OR agent_runs.run_id IS NOT excluded.run_id OR (excluded.profile_json IS NOT NULL AND agent_runs.profile_json IS NOT excluded.profile_json) OR agent_runs.main IS NOT excluded.main OR (agent_runs.starter_session IS NULL AND excluded.starter_session IS NOT NULL)').run(org,id,session,machine,String(run),profile?JSON.stringify(profile):null,main?1:0,starterSession);
|
|
381
|
+
db.exec('COMMIT');
|
|
382
|
+
}catch(error){try{db.exec('ROLLBACK');}catch{}throw error;}finally{db.close();}
|
|
383
|
+
}
|
|
384
|
+
export function pendingAgentRuns(root,org){const db=store(root);try{return db.prepare('SELECT * FROM agent_runs WHERE org=? AND published=0 ORDER BY rowid LIMIT 100').all(org);}finally{db.close();}}
|
|
385
|
+
/** Session references come from the bound runtime, never from a model's requested agent id. */
|
|
386
|
+
export function agentRunForSession(root, references) {
|
|
387
|
+
const db = store(root);
|
|
388
|
+
try {
|
|
389
|
+
const rows = references.filter(Boolean).flatMap(ref => {
|
|
390
|
+
const aliases=db.prepare('SELECT r.* FROM agent_runtime_sessions a JOIN agent_runs r ON r.org=a.org AND r.session_ref=a.session_ref WHERE a.runtime_ref=?').all(ref);
|
|
391
|
+
return aliases.length?aliases:db.prepare('SELECT * FROM agent_runs WHERE session_ref=?').all(ref);
|
|
392
|
+
});
|
|
393
|
+
const owners = new Map(rows.map(row => [JSON.stringify([row.org, row.agent_id]), row]));
|
|
394
|
+
if (owners.size > 1) throw new Error('session references have conflicting agent ownership');
|
|
395
|
+
return owners.values().next().value ?? null;
|
|
396
|
+
} finally { db.close(); }
|
|
397
|
+
}
|
|
398
|
+
/** G3: a session's usage as its harness recorded it, kept with the run that owned it. */
|
|
399
|
+
export function recordRunUsage(root,org,session,usage){
|
|
400
|
+
const db=store(root);try{db.prepare('UPDATE agent_runs SET usage_json=? WHERE org=? AND session_ref=?').run(JSON.stringify(usage??[]),org,session);}finally{db.close();}
|
|
401
|
+
}
|
|
402
|
+
/** The runs whose ended sessions have no usage recorded yet. */
|
|
403
|
+
export function runsAwaitingUsage(root,org){
|
|
404
|
+
const db=store(root);try{return db.prepare('SELECT * FROM agent_runs WHERE org=? AND usage_json IS NULL ORDER BY rowid LIMIT 50').all(org);}finally{db.close();}
|
|
405
|
+
}
|
|
406
|
+
/** Usage records per agent id: every session this home ran for it. */
|
|
407
|
+
export function agentUsage(root){
|
|
408
|
+
const db=store(root),by=new Map();
|
|
409
|
+
try{for(const row of db.prepare('SELECT agent_id,session_ref,usage_json FROM agent_runs WHERE usage_json IS NOT NULL').all()){
|
|
410
|
+
const list=by.get(row.agent_id)??[];list.push(...JSON.parse(row.usage_json).map(u=>({...u,session:row.session_ref})));by.set(row.agent_id,list);
|
|
411
|
+
}}finally{db.close();}
|
|
412
|
+
return by;
|
|
413
|
+
}
|
|
414
|
+
/** The budget a card run would exceed, as a sentence, or null (G3: a per-action gate, never a pause). */
|
|
415
|
+
export function runBudgetRefusal(root,agent,budgets,now){
|
|
416
|
+
const used=agentUsage(root).get(agent)??[],day=now.slice(0,10),month=now.slice(0,7);
|
|
417
|
+
for(const budget of budgets??[]){
|
|
418
|
+
let tokens=0,cost=0;
|
|
419
|
+
for(const u of used){
|
|
420
|
+
if(budget.period==='day'&&!u.at.startsWith(day))continue;
|
|
421
|
+
if(budget.period==='month'&&!u.at.startsWith(month))continue;
|
|
422
|
+
if(budget.period==='run')continue;
|
|
423
|
+
tokens+=(u.input_tokens??0)+(u.output_tokens??0);cost+=u.cost?.amount??0;
|
|
424
|
+
}
|
|
425
|
+
if(budget.limit?.tokens!=null&&tokens>=budget.limit.tokens)return `agent ${agent} has used ${tokens} of its ${budget.limit.tokens}-token ${budget.period} budget`;
|
|
426
|
+
if(budget.limit?.cost!=null&&cost>=budget.limit.cost.amount)return `agent ${agent} has spent ${cost} of its ${budget.limit.cost.amount} ${budget.limit.cost.currency} ${budget.period} budget`;
|
|
427
|
+
}
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
export function publishAgentRun(root,org,session){const db=store(root);try{db.prepare('UPDATE agent_runs SET published=1 WHERE org=? AND session_ref=?').run(org,session);}finally{db.close();}}
|
|
431
|
+
export function agentPreamble(agent,{main=true,previous=[]}={}){
|
|
432
|
+
const {identity:a,intended,assignments=[]}=agent;
|
|
433
|
+
return `You are agent ${a.path} (${a.id}), ${main?'its main session':'a concurrent session'}.${a.synced===false?' This identity was minted on this machine and is not yet declared on a Teams server; it keeps this id when it is.':''}\nSponsor: ${a.sponsor??'none yet'}; parent: ${a.parent??'none'}; lineage: ${JSON.stringify(a.lineage)}.\nAssignments: ${assignments.map(value=>`${value.kind} ${value.target}, role ${value.role}`).join("; ")}; profile: ${a.profile}; permission layers: ${JSON.stringify(intended.resolved.permissions.layers)}.\nAsk again with supercode agent whoami. List your sessions with supercode agent sessions; read a transcript only when needed.${previous.length?'\nEarlier sessions:\n'+previous.map(s=>`${s.session} · ${s.machine??'unknown machine'} · ended ${s.ended_at??'live'} · ${s.end_reason??''}`).join('\n'):''}`;
|
|
434
|
+
}
|
|
435
|
+
export function agentProfileMismatch(intent,resolved){return compareAgentProfile(intent?.resolved??intent,resolved);}
|
|
436
|
+
|
|
437
|
+
export function agentEnvironment(agent,{root,context,session=null,main=true}={}) {
|
|
438
|
+
const a=agent.identity;
|
|
439
|
+
return {SUPERCODE_AGENT_ID:a.id,SUPERCODE_AGENT_NAME:a.name,SUPERCODE_AGENT_PATH:a.path,
|
|
440
|
+
SUPERCODE_AGENT_ORG:a.org,SUPERCODE_AGENT_HOME:root,SUPERCODE_AGENT_CONTEXT:context??'',
|
|
441
|
+
SUPERCODE_AGENT_MAIN:main?'1':'0',SUPERCODE_AGENT_SYNCED:a.synced===false?'0':'1',SUPERCODE_AGENT_ASSIGNMENTS:JSON.stringify(agent.assignments??[]),
|
|
442
|
+
...(session?{SUPERCODE_AGENT_SESSION:session}:{})};
|
|
443
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The orchestrator's synchronous host reaches Teams through the installed neutral SDK.
|
|
3
|
+
import { fromContext } from '@volter/teams/context';
|
|
4
|
+
import { supercodeHome } from '@volter/teams/home';
|
|
5
|
+
import { createHash } from 'node:crypto';
|
|
6
|
+
import { openMachine } from '@volter/teams/machine-door';
|
|
7
|
+
import { StreamRpc } from '@volter/teams/client';
|
|
8
|
+
let input='';for await(const chunk of process.stdin)input+=chunk;
|
|
9
|
+
try{
|
|
10
|
+
const {op,args=[],context}=JSON.parse(input);
|
|
11
|
+
const {client,context:scope}=fromContext({supercodeHome:supercodeHome(),name:context??process.env.SUPERCODE_CONTEXT});
|
|
12
|
+
const team=client.team(scope.team_id),options={signal:AbortSignal.timeout(20000)};
|
|
13
|
+
let result;
|
|
14
|
+
if(op==='scope')result={server:scope.origin,server_id:scope.server_id,org:scope.team_id,principal:scope.principal_id};
|
|
15
|
+
else if(op==='root')result=await team.agents.root(options);
|
|
16
|
+
else if(op==='get')result=await team.agents.get(args[0],options);
|
|
17
|
+
else if(op==='management')result=await team.agents.management(args[0],options);
|
|
18
|
+
else if(op==='profile')result=await team.agents.update(args[0],{profile:args[1]},{...options,ifMatch:args[2]});
|
|
19
|
+
else if(op==='reparent')result=await team.agents.update(args[0],{parent:args[1]},{...options,ifMatch:args[2]});
|
|
20
|
+
else if(op==='declare')result=await team.agents.declare(args[0],{...options,idempotencyKey:args[1]});
|
|
21
|
+
else if(op==='sessions')result=await team.agents.sessions(args[0],args[1]??{},options);
|
|
22
|
+
else if(op==='ownSession')result=await team.agents.ownSession(args[0],args[1],{...options,idempotencyKey:args[2]});
|
|
23
|
+
else if(op==='session')result=await team.sessions.get(args[0]).identity(options);
|
|
24
|
+
else if(op==='end'){
|
|
25
|
+
const agent=(await team.agents.get(args[0],options)).data;
|
|
26
|
+
result=agent.state==='ended'?{data:{id:agent.id,state:'ended'}}:await team.agents.end(agent.id,{reason:args[1]},{...options,ifMatch:agent.revision,idempotencyKey:args[2]});
|
|
27
|
+
}
|
|
28
|
+
else if(op==='reader')result=await team.agents.delegateReader(args[0],{},{...options,ifMatch:args[1]});
|
|
29
|
+
else if(op==='bindContext'){
|
|
30
|
+
const key=createHash('sha256').update(`${scope.origin}/${scope.team_id}/${args[0]}`).digest('hex');
|
|
31
|
+
const channel=await openMachine({machine:args[2]??null,context:context??process.env.SUPERCODE_CONTEXT});
|
|
32
|
+
try{const rpc=new StreamRpc(await channel.open('node'));result=await rpc.call('harness.v1.agents.bindSession',{session:args[1],context:`agent-${key.slice(0,32)}`,assignments:args[3]??[],intended:args[4]??null});}
|
|
33
|
+
finally{channel.close();}
|
|
34
|
+
}
|
|
35
|
+
else if(op==='readerContext'){
|
|
36
|
+
const identity=await team.agents.get(args[0],options);
|
|
37
|
+
const reader=await team.agents.delegateReader(args[0],{expires_in_ms:86400000},{...options,ifMatch:identity.data.revision});
|
|
38
|
+
const channel=await openMachine({machine:args[1]??null,context:context??process.env.SUPERCODE_CONTEXT});
|
|
39
|
+
try{const rpc=new StreamRpc(await channel.open('node'));result=await rpc.call('harness.v1.agents.context',{origin:scope.origin,team:scope.team_id,agent:args[0],credential:reader.data});}
|
|
40
|
+
finally{channel.close();}
|
|
41
|
+
}
|
|
42
|
+
else if(op==='resolveIdentity')result=await team.identity.resolve(args[0],options);
|
|
43
|
+
else if(op==='find'){
|
|
44
|
+
let after='',found=null;
|
|
45
|
+
do{
|
|
46
|
+
const page=await team.agents.list({after,limit:200},options);
|
|
47
|
+
found=page.items.find(agent=>agent.name===args[0]&&agent.parent===args[1]&&agent.state!=='ended')??null;
|
|
48
|
+
if(found)break;after=page.next_after;
|
|
49
|
+
}while(after);
|
|
50
|
+
result={data:found};
|
|
51
|
+
}else throw Object.assign(new Error('unsupported agent door'),{code:'invalid_request'});
|
|
52
|
+
process.stdout.write(JSON.stringify(result)+'\n');
|
|
53
|
+
}catch(error){process.stderr.write(JSON.stringify({status:error.status,code:error.code??'unavailable',message:error.message})+'\n');process.exitCode=1;}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// A synchronous board process delegates one request to the public daemon door.
|
|
3
|
+
// This helper owns neither credentials nor machine state; the SDK opens the admitted channel.
|
|
4
|
+
import { openMachine } from '@volter/teams/machine-door';
|
|
5
|
+
import { StreamRpc, harnessTransport } from '@volter/teams/client';
|
|
6
|
+
import { SupercodeHarnessClient } from '@volter/supercode-harness-sdk';
|
|
7
|
+
let input = ''; for await (const chunk of process.stdin) input += chunk;
|
|
8
|
+
let channel;
|
|
9
|
+
try {
|
|
10
|
+
const { machine, method, params = {} } = JSON.parse(input);
|
|
11
|
+
if (!method.startsWith('harness.v1.')) throw new Error('the runtime door accepts harness.v1 methods');
|
|
12
|
+
channel = await openMachine({machine});
|
|
13
|
+
let result;
|
|
14
|
+
if (method.startsWith('harness.v1.sessions.')) {
|
|
15
|
+
// A session's records are the harness's own service, spoken by its SDK over the machine's harness stream.
|
|
16
|
+
const client = new SupercodeHarnessClient({ transport: harnessTransport(channel) });
|
|
17
|
+
try { await client.start?.(); result = await client.request(method, params); } finally { await client.close?.(); }
|
|
18
|
+
} else result = await new StreamRpc(await channel.open('node')).call(method,params);
|
|
19
|
+
process.stdout.write(JSON.stringify(result)+'\n');
|
|
20
|
+
} catch (error) {
|
|
21
|
+
process.stderr.write(JSON.stringify({code:error.code??'unavailable',message:error.message})+'\n');
|
|
22
|
+
process.exitCode = 1;
|
|
23
|
+
} finally { channel?.close(); }
|